UNPKG

es-dev-server

Version:

Development server for modern web apps

117 lines 5.51 kB
"use strict"; 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