es-dev-server
Version:
Development server for modern web apps
117 lines • 5.51 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.polyfillsLoaderPlugin = void 0;
const tslib_1 = require("tslib");
const path_1 = tslib_1.__importDefault(require("path"));
const inject_polyfills_loader_1 = require("../utils/inject-polyfills-loader");
const utils_1 = require("../utils/utils");
const user_agent_compat_1 = require("../utils/user-agent-compat");
/**
* Creates plugin which injects polyfills and code into HTML pages which allows
* it to run on legacy browsers.
*/
function polyfillsLoaderPlugin(config) {
const { compatibilityMode, rootDir, polyfillsLoaderConfig = {} } = config;
// index html data, keyed by url
const indexHTMLData = new Map();
// polyfills, keyed by request path
const polyfills = new Map();
return {
async serve(context) {
const uaCompat = user_agent_compat_1.getUserAgentCompat(context);
/**
* serve extracted inline module if url matches. an inline module requests has this
* structure:
* `/inline-script-<index>?source=<index-html-path>`
* for example:
* `/inline-script-2?source=/src/index-html`
* source query parameter is the index.html the inline module came from, index is the index
* of the inline module in that index.html. We use these to look up the correct code to
* serve
*/
if (utils_1.isInlineScript(context.url)) {
const sourcePath = context.URL.searchParams.get('source');
if (!sourcePath) {
throw new Error(`${context.url} is missing a source param`);
}
const data = indexHTMLData.get(`${uaCompat.browserTarget}${sourcePath}`);
if (!data) {
return undefined;
}
const name = path_1.default.basename(context.path);
const inlineScript = data.inlineScripts.find(f => f.path.split('?')[0] === name);
if (!inlineScript) {
throw new Error(`Could not find inline module for ${context.url}`);
}
return {
body: inlineScript.content,
headers: {
'cache-control': 'no-cache',
'last-modified': data.lastModified,
},
};
}
// serve polyfill from memory if url matches
const polyfill = polyfills.get(context.url);
if (polyfill) {
// aggresively cache polyfills, they are hashed so content changes bust the cache
return { body: polyfill, headers: { 'cache-control': 'public, max-age=31536000' } };
}
},
async transform(context) {
// check if we are serving a HTML file
if (!context.response.is('html')) {
return undefined;
}
const uaCompat = user_agent_compat_1.getUserAgentCompat(context);
const lastModified = context.response.headers['last-modified'];
// return cached index.html if it did not change
const data = indexHTMLData.get(`${uaCompat.browserTarget}${context.path}`);
// if there is no lastModified cached, the HTML file is not served from the
// file system
if ((data === null || data === void 0 ? void 0 : data.lastModified) && (data === null || data === void 0 ? void 0 : data.lastModified) === lastModified) {
return { body: data.indexHTML };
}
const indexFilePath = path_1.default.join(rootDir, utils_1.toFilePath(context.path));
try {
// transforms index.html to make the code load correctly with the right polyfills and shims
const result = await inject_polyfills_loader_1.injectPolyfillsLoader({
htmlString: context.body,
indexUrl: context.url,
indexFilePath,
compatibilityMode,
polyfillsLoaderConfig,
uaCompat,
});
// set new index.html
context.body = result.indexHTML;
const polyfillsMap = new Map();
result.polyfills.forEach(file => {
polyfillsMap.set(file.path, file);
});
// cache index for later use
indexHTMLData.set(`${uaCompat.browserTarget}${context.url}`, {
...result,
inlineScripts: result.inlineScripts,
lastModified,
});
// cache polyfills for serving
result.polyfills.forEach(p => {
let root = context.path.endsWith('/') ? context.path : path_1.default.posix.dirname(context.path);
if (!root.endsWith('/')) {
root = `${root}/`;
}
polyfills.set(`${root}${utils_1.toBrowserPath(p.path)}`, p.content);
});
}
catch (error) {
if (error instanceof utils_1.RequestCancelledError) {
return;
}
throw error;
}
},
};
}
exports.polyfillsLoaderPlugin = polyfillsLoaderPlugin;
//# sourceMappingURL=polyfillsLoaderPlugin.js.map