UNPKG

@web/polyfills-loader

Version:

Generate loader for loading browser polyfills based on feature detection

96 lines 4.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.injectPolyfillsLoader = void 0; const parse5_1 = require("parse5"); const parse5_utils_1 = require("@web/parse5-utils"); const createPolyfillsLoader_js_1 = require("./createPolyfillsLoader.js"); const utils_js_1 = require("./utils.js"); function injectImportMapPolyfill(headAst, originalScript, type) { const systemJsScript = (0, parse5_utils_1.createScript)({ type }, (0, parse5_utils_1.getTextContent)(originalScript)); (0, parse5_utils_1.insertBefore)(headAst, systemJsScript, originalScript); } function findImportMapScripts(document) { const scripts = (0, parse5_utils_1.findElements)(document, script => (0, parse5_utils_1.getAttribute)(script, 'type') === 'importmap'); const inline = []; const external = []; for (const script of scripts) { if ((0, parse5_utils_1.getAttribute)(script, 'src')) { external.push(script); } else { inline.push(script); } } return { inline, external }; } function injectImportMapPolyfills(documentAst, headAst, cfg) { const importMapScripts = findImportMapScripts(documentAst); if (importMapScripts.external.length === 0 && importMapScripts.inline.length === 0) { return; } const polyfillSystemJs = (0, utils_js_1.hasFileOfType)(cfg, utils_js_1.fileTypes.SYSTEMJS); const importMaps = [...importMapScripts.external, ...importMapScripts.inline]; importMaps.forEach(originalScript => { if (polyfillSystemJs) { injectImportMapPolyfill(headAst, originalScript, 'systemjs-importmap'); } }); } function injectLoaderScript(bodyAst, polyfillsLoader, cfg) { let loaderScript; if (cfg.externalLoaderScript) { const loaderScriptFile = polyfillsLoader.polyfillFiles.find(f => f.path.endsWith('loader.js')); if (!loaderScriptFile) { throw new Error('Missing polyfills loader script file'); } loaderScript = (0, parse5_utils_1.createScript)({ src: loaderScriptFile.path }); } else { loaderScript = (0, parse5_utils_1.createScript)({}, polyfillsLoader.code); } (0, parse5_utils_1.appendChild)(bodyAst, loaderScript); } function injectPrefetchLinks(headAst, cfg) { for (const file of cfg.modern.files) { const { path } = file; const href = path.startsWith('.') || path.startsWith('/') ? path : `./${path}`; if (file.type === utils_js_1.fileTypes.MODULE) { (0, parse5_utils_1.appendChild)(headAst, (0, parse5_utils_1.createElement)('link', { rel: 'preload', href, as: 'script', crossorigin: 'anonymous', })); } else { (0, parse5_utils_1.appendChild)(headAst, (0, parse5_utils_1.createElement)('link', { rel: 'preload', href, as: 'script' })); } } } /** * Transforms an index.html file, injecting a polyfills loader for * compatibility with older browsers. */ async function injectPolyfillsLoader(htmlString, cfg) { const documentAst = (0, parse5_1.parse)(htmlString); const headAst = (0, parse5_utils_1.findElement)(documentAst, e => (0, parse5_utils_1.getTagName)(e) === 'head'); const bodyAst = (0, parse5_utils_1.findElement)(documentAst, e => (0, parse5_utils_1.getTagName)(e) === 'body'); if (!headAst || !bodyAst) { throw new Error(`Invalid index.html: missing <head> or <body>`); } const polyfillsLoader = await (0, createPolyfillsLoader_js_1.createPolyfillsLoader)(cfg); if (polyfillsLoader === null) { return { htmlString, polyfillFiles: [] }; } if (cfg.preload) { injectPrefetchLinks(headAst, cfg); } injectImportMapPolyfills(documentAst, headAst, cfg); injectLoaderScript(bodyAst, polyfillsLoader, cfg); return { htmlString: (0, parse5_1.serialize)(documentAst), polyfillFiles: polyfillsLoader.polyfillFiles, }; } exports.injectPolyfillsLoader = injectPolyfillsLoader; //# sourceMappingURL=injectPolyfillsLoader.js.map