es-dev-server-rollup
Version:
Use rollup plugins in es-dev-server
185 lines (184 loc) • 9.6 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapRollupPlugin = void 0;
const path_1 = __importDefault(require("path"));
const whatwg_url_1 = __importDefault(require("whatwg-url"));
const es_dev_server_1 = require("es-dev-server");
const dom5_fork_1 = require("@open-wc/building-utils/dom5-fork");
// @ts-ignore
const building_utils_1 = require("@open-wc/building-utils");
const parse5_1 = require("parse5");
const utils_1 = require("./utils");
const PluginContext_1 = require("./PluginContext");
const NULL_BYTE_PARAM = 'es-dev-server-rollup-null-byte';
function wrapRollupPlugin(rollupPlugin, rollupOptions = {}) {
const transformedFiles = new Set();
let transformedOptions;
let fileWatcher;
let config;
let rootDir;
const edsPlugin = {
serverStart(args) {
var _a, _b, _c;
({ fileWatcher, config } = args);
({ rootDir } = config);
const rollupPluginContext = PluginContext_1.createPluginContext(fileWatcher, config, edsPlugin);
// call the options and buildStart hooks
transformedOptions = (_b = (_a = rollupPlugin.options) === null || _a === void 0 ? void 0 : _a.call(rollupPluginContext, rollupOptions)) !== null && _b !== void 0 ? _b : rollupOptions;
(_c = rollupPlugin.buildStart) === null || _c === void 0 ? void 0 : _c.call(rollupPluginContext, transformedOptions);
},
async resolveImport({ source, context }) {
var _a;
// if we just transformed this file and the import is an absolute file path
// we need to rewrite it to a browser path
const injectedFilePath = transformedFiles.has(context.path) && source.startsWith(rootDir);
if (!injectedFilePath && !rollupPlugin.resolveId) {
return;
}
if (!path_1.default.isAbsolute(source) && whatwg_url_1.default.parseURL(source) != null) {
// don't resolve relative and valid urls
return source;
}
const requestedFile = context.path.endsWith('/')
? `${context.path}index.html`
: context.path;
const filePath = path_1.default.join(rootDir, requestedFile);
const rollupPluginContext = PluginContext_1.createPluginContext(fileWatcher, config, edsPlugin, context);
// if the import was already a fully resolved file path, it was probably injected by a plugin.
// in that case use that instead of resolving it through a plugin hook. this puts the resolved file
// path through the regular logic to turn it into a relative browser import
// otherwise call the resolveID hook on the plugin
const result = injectedFilePath
? source
: await ((_a = rollupPlugin.resolveId) === null || _a === void 0 ? void 0 : _a.call(rollupPluginContext, source, filePath));
let resolvedImportFilePath = undefined;
if (typeof result === 'string') {
resolvedImportFilePath = result;
}
else if (typeof result === 'object' && typeof (result === null || result === void 0 ? void 0 : result.id) === 'string') {
resolvedImportFilePath = result.id;
}
if (!resolvedImportFilePath) {
return undefined;
}
const hasNullByte = resolvedImportFilePath.includes('\0');
const withoutNullByte = hasNullByte
? resolvedImportFilePath.replace(new RegExp('\0', 'g'), '')
: resolvedImportFilePath;
if (withoutNullByte.startsWith(rootDir)) {
const resolveRelativeTo = path_1.default.extname(filePath)
? path_1.default.dirname(filePath)
: filePath;
const relativeImportFilePath = path_1.default.relative(resolveRelativeTo, withoutNullByte);
const resolvedImportPath = `${utils_1.toBrowserPath(relativeImportFilePath)}`;
const prefixedImportPath = resolvedImportPath.startsWith('/') ||
resolvedImportPath.startsWith('.')
? resolvedImportPath
: `./${resolvedImportPath}`;
if (!hasNullByte) {
return prefixedImportPath;
}
else {
const suffix = `${NULL_BYTE_PARAM}=${encodeURIComponent(resolvedImportFilePath)}`;
if (prefixedImportPath.includes('?')) {
return `${prefixedImportPath}&${suffix}`;
}
return `${prefixedImportPath}?${suffix}`;
}
}
// if the resolved import includes a null byte (\0) there is some special logic
// these often are not valid file paths, so the browser cannot request them.
// we rewrite them to a special URL which we deconstruct later when we load the file
if (resolvedImportFilePath.includes('\0')) {
return `${es_dev_server_1.virtualFilePrefix}?${NULL_BYTE_PARAM}=${encodeURIComponent(resolvedImportFilePath)}`;
}
return resolvedImportFilePath;
},
async serve(context) {
var _a;
if (!rollupPlugin.load) {
return;
}
let filePath;
if (context.URL.searchParams.has(NULL_BYTE_PARAM)) {
// if this was a special URL constructed in resolveImport to handle null bytes,
// the file path is stored in the search paramter
filePath = context.URL.searchParams.get(NULL_BYTE_PARAM);
}
else {
filePath = path_1.default.join(rootDir, context.path);
}
const rollupPluginContext = PluginContext_1.createPluginContext(fileWatcher, config, edsPlugin, context);
const result = await ((_a = rollupPlugin.load) === null || _a === void 0 ? void 0 : _a.call(rollupPluginContext, filePath));
if (typeof result === 'string') {
return { body: result, type: 'js' };
}
if (typeof (result === null || result === void 0 ? void 0 : result.code) === 'string') {
return { body: result.code, type: 'js' };
}
return undefined;
},
async transform(context) {
var _a, _b;
if (!rollupPlugin.transform) {
return;
}
if (context.response.is('js')) {
const filePath = path_1.default.join(rootDir, context.path);
const rollupPluginContext = PluginContext_1.createPluginContext(fileWatcher, config, edsPlugin, context);
const result = await ((_a = rollupPlugin.transform) === null || _a === void 0 ? void 0 : _a.call(rollupPluginContext, context.body, filePath));
let transformedCode = undefined;
if (typeof result === 'string') {
transformedCode = result;
}
if (typeof result === 'object' && typeof (result === null || result === void 0 ? void 0 : result.code) === 'string') {
transformedCode = result.code;
}
if (transformedCode) {
transformedFiles.add(context.path);
return { body: transformedCode };
}
return;
}
if (context.response.is('html')) {
const requestedFile = context.path.endsWith('/')
? `${context.path}index.html`
: context.path;
const filePath = path_1.default.join(rootDir, requestedFile);
let changed = false;
const documentAst = parse5_1.parse(context.body);
const scriptNodes = building_utils_1.findJsScripts(documentAst, {
jsScripts: true,
jsModules: true,
inlineJsScripts: true,
});
for (const node of scriptNodes) {
const code = dom5_fork_1.getTextContent(node);
const rollupPluginContext = PluginContext_1.createPluginContext(fileWatcher, config, edsPlugin, context);
const result = await ((_b = rollupPlugin.transform) === null || _b === void 0 ? void 0 : _b.call(rollupPluginContext, code, filePath));
let transformedCode;
if (typeof result === 'string') {
transformedCode = result;
}
else if (typeof result === 'object' &&
typeof (result === null || result === void 0 ? void 0 : result.code) === 'string') {
transformedCode = result.code;
}
if (transformedCode) {
changed = true;
dom5_fork_1.setTextContent(node, transformedCode);
}
}
if (changed) {
transformedFiles.add(context.path);
return { body: parse5_1.serialize(documentAst) };
}
}
},
};
return edsPlugin;
}
exports.wrapRollupPlugin = wrapRollupPlugin;
;