From 16918ddb7d3ce0ed0e53a1fd534127ec60ca05f2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 11 Oct 2021 17:59:31 +0200 Subject: [PATCH] ie11 build wip --- package.json | 1 + scripts/build-plugins/legacy-build.js | 137 ++++++++++++++++++++++++ scripts/build-plugins/manifest.js | 2 +- scripts/build-plugins/service-worker.js | 11 +- src/platform/web/index.html | 22 ++-- vite.config.js | 23 +++- yarn.lock | 31 ++++++ 7 files changed, 208 insertions(+), 19 deletions(-) create mode 100644 scripts/build-plugins/legacy-build.js diff --git a/package.json b/package.json index 7cced96b..2c02fb1f 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@rollup/plugin-multi-entry": "^4.0.0", "@typescript-eslint/eslint-plugin": "^4.29.2", "@typescript-eslint/parser": "^4.29.2", + "@vitejs/plugin-legacy": "^1.6.1", "autoprefixer": "^10.2.6", "cheerio": "^1.0.0-rc.3", "commander": "^6.0.0", diff --git a/scripts/build-plugins/legacy-build.js b/scripts/build-plugins/legacy-build.js new file mode 100644 index 00000000..3d069d4d --- /dev/null +++ b/scripts/build-plugins/legacy-build.js @@ -0,0 +1,137 @@ +const { build } = require("vite"); +const path = require("path"); +let babel; // big import, only do so when used below +const VIRTUAL_ENTRY = "hydrogen:legacy-entry"; + +module.exports = function legacyBuild(entryModuleId, entryImportReplacements, chunkName, extraImports) { + let parentRoot; + let code; + let legacyBundleFileName; + return { + name: "hydrogen:legacyBuild", + apply: "build", + configResolved: config => { + parentRoot = config.root; + }, + async moduleParsed(info) { + if (info.id === entryModuleId) { + code = info.code; + } + }, + async buildEnd() { + if (!code) { + throw new Error("couldnt find entry"); + } + for (const [importSource, newImportSource] of Object.entries(entryImportReplacements)) { + code = replaceImport(this, code, importSource, newImportSource); + } + code = addExtraImports(code, extraImports); + const mainChunk = await buildLegacyChunk(parentRoot, chunkName, code); + this.emitFile({ + type: "asset", + source: mainChunk.code, + fileName: mainChunk.fileName, + name: mainChunk.name + }); + legacyBundleFileName = mainChunk.fileName; + }, + transformIndexHtml: { + transform(html) { + if (!legacyBundleFileName) { + throw new Error("no bundle"); + } + return [{ + tag: "script", + attrs: {type: "text/javascript", nomodule: true, src: legacyBundleFileName}, + injectTo: "head" + }]; + }, + }, + } +} + + +function replaceImport(pluginCtx, code, importSource, newImportSource) { + const ast = pluginCtx.parse(code); + for (const node of ast.body) { + if (node.type === "ImportDeclaration") { + const sourceNode = node.source; + if (sourceNode.value === importSource) { + code = code.substr(0, sourceNode.start) + JSON.stringify(newImportSource) + code.substr(sourceNode.end); + return code; + } + } + } + throw new Error(`Could not find import ${JSON.stringify(importSource)} to replace`); +} + +function addExtraImports(code, extraImports) { + return extraImports.map(i => `import ${JSON.stringify(i)};`).join("\n") + code; +} + +async function buildLegacyChunk(root, chunkName, code) { + if (!babel) { + babel = require('@rollup/plugin-babel'); + } + // compile down to whatever IE 11 needs + const babelPlugin = babel.babel({ + babelHelpers: 'bundled', + exclude: 'node_modules/**', + presets: [ + [ + "@babel/preset-env", + { + useBuiltIns: "entry", + corejs: "3.4", + targets: "IE 11", + // we provide our own promise polyfill (es6-promise) + // with support for synchronous flushing of + // the queue for idb where needed + exclude: ["es.promise", "es.promise.all-settled", "es.promise.finally"] + } + ] + ] + }); + const bundle = await build({ + root, + configFile: false, + logLevel: 'error', + build: { + write: false, + target: false, + minify: true, + assetsInlineLimit: 0, + polyfillModulePreload: false, + rollupOptions: { + input: { + [chunkName]: VIRTUAL_ENTRY + }, + output: { + format: "iife", + manualChunks: undefined + } + }, + }, + plugins: [ + { + name: "hydrogen:resolve-legacy-entry", + resolveId(id, importer) { + if (id === VIRTUAL_ENTRY) { + return id; + } else if (importer === VIRTUAL_ENTRY && id.startsWith("./")) { + return this.resolve(path.join(root, id)); + } + }, + load(id) { + if (id === VIRTUAL_ENTRY) { + return code; + } + } + }, + babelPlugin + ] + }); + const assets = Array.isArray(bundle.output) ? bundle.output : [bundle.output]; + const mainChunk = assets.find(a => a.name === chunkName); + return mainChunk; +} diff --git a/scripts/build-plugins/manifest.js b/scripts/build-plugins/manifest.js index bcd96fa4..560bce68 100644 --- a/scripts/build-plugins/manifest.js +++ b/scripts/build-plugins/manifest.js @@ -5,7 +5,7 @@ module.exports = function injectWebManifest(manifestFile) { let root; let manifestHref; return { - name: "injectWebManifest", + name: "hydrogen:injectWebManifest", apply: "build", configResolved: config => { root = config.root; diff --git a/scripts/build-plugins/service-worker.js b/scripts/build-plugins/service-worker.js index 901f0395..155c798b 100644 --- a/scripts/build-plugins/service-worker.js +++ b/scripts/build-plugins/service-worker.js @@ -13,7 +13,7 @@ module.exports = function injectServiceWorker(swFile) { let version; let manifestHref; return { - name: "injectServiceWorker", + name: "hydrogen:injectServiceWorker", apply: "build", enforce: "post", configResolved: config => { @@ -26,8 +26,13 @@ module.exports = function injectServiceWorker(swFile) { let swSource = await fs.readFile(absoluteSwFile, {encoding: "utf8"}); const assets = Object.values(bundle).filter(a => a.type === "asset"); const cachedFileNames = assets.map(o => o.fileName).filter(fileName => fileName !== "index.html"); + const r = Object.entries(bundle).find(([key, asset]) => key.includes("index.html")); + const index = assets.find(o => o.fileName === "index.html"); + if (!index) { + console.log("index not found", index, r); + } const uncachedFileContentMap = { - "index.html": assets.find(o => o.fileName === "index.html").source, + "index.html": index.source, "sw.js": swSource }; const globalHash = getBuildHash(cachedFileNames, uncachedFileContentMap); @@ -55,7 +60,7 @@ function getBuildHash(cachedFileNames, uncachedFileContentMap) { } const NON_PRECACHED_JS = [ - "hydrogen-legacy.js", + "hydrogen-legacy", "olm_legacy.js", // most environments don't need the worker "main.js" diff --git a/src/platform/web/index.html b/src/platform/web/index.html index d0718098..a99edde8 100644 --- a/src/platform/web/index.html +++ b/src/platform/web/index.html @@ -19,19 +19,21 @@ diff --git a/vite.config.js b/vite.config.js index e0dd0f99..45ab94c9 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,9 +1,15 @@ const injectWebManifest = require("./scripts/build-plugins/manifest"); const injectServiceWorker = require("./scripts/build-plugins/service-worker"); +const legacyBuild = require("./scripts/build-plugins/legacy-build"); const fs = require("fs"); const path = require("path"); - +// we could also just import {version} from "../../package.json" where needed, +// but this won't work in the service worker yet as it is not transformed yet +// TODO: we should emit a chunk early on and then transform the asset again once we know all the other assets to cache const version = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8")).version; +const {defineConfig} = require("vite"); +let polyfillSrc; +let polyfillRef; export default { public: false, @@ -14,18 +20,25 @@ export default { resolve: { alias: { "safe-buffer": "./scripts/package-overrides/safe-buffer/index.js", - "buffer": "./scripts/package-overrides/buffer/index.js" + "buffer": "./scripts/package-overrides/buffer/index.js", } }, build: { outDir: "../../../target", emptyOutDir: true, - minify: true, - sourcemap: true + minify: false, + sourcemap: false, + assetsInlineLimit: 0, + polyfillModulePreload: false, }, plugins: [ + legacyBuild(path.join(__dirname, "src/platform/web/index.html?html-proxy&index=0.js"), { + "./Platform": "./LegacyPlatform" + }, "hydrogen-legacy", [ + './legacy-polyfill', + ]), injectWebManifest("assets/manifest.json"), - injectServiceWorker("sw.js") + injectServiceWorker("sw.js"), ], define: { "HYDROGEN_VERSION": JSON.stringify(version) diff --git a/yarn.lock b/yarn.lock index d2e3035d..30c71c52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -825,6 +825,11 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/standalone@^7.15.7": + version "7.15.8" + resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.15.8.tgz#3cb40b81892a702968a3e0bba2bdd1115f034876" + integrity sha512-EF2uQLeuwflnPRGetWH2Z400ITOSK7YbkXIKxY91EWSiOJ8xsbupT3sx3sFRwVyQgjsHSILFDzLcSo/rGspLhQ== + "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -1294,6 +1299,17 @@ "@typescript-eslint/types" "4.29.2" eslint-visitor-keys "^2.0.0" +"@vitejs/plugin-legacy@^1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-legacy/-/plugin-legacy-1.6.1.tgz#45f0e006de2d25758151b098b8dcb912c62a95dc" + integrity sha512-isBi2ti+AlCZUpfA1P6L8gseltBy/qi6Rsi92aDzeL2elpwXgN4Hv/xLS2UUSSj9F0mFmxXCYPWlBPaJnlYamQ== + dependencies: + "@babel/standalone" "^7.15.7" + core-js "^3.18.1" + magic-string "^0.25.7" + regenerator-runtime "^0.13.9" + systemjs "^6.10.3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1898,6 +1914,11 @@ core-js@^2.5.3: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== +core-js@^3.18.1: + version "3.18.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.2.tgz#63a551e8a29f305cd4123754846e65896619ba5b" + integrity sha512-zNhPOUoSgoizoSQFdX1MeZO16ORRb9FFQLts8gSYbZU5FcgXhp24iMWMxnOQo5uIaIG7/6FA/IqJPwev1o9ZXQ== + core-js@^3.6.5: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" @@ -4554,6 +4575,11 @@ regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regenerator-runtime@^0.13.9: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regenerator-transform@^0.14.2: version "0.14.5" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" @@ -5118,6 +5144,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +systemjs@^6.10.3: + version "6.10.3" + resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.10.3.tgz#7e783fccb58232f1d9eb05c7e1a661268945cade" + integrity sha512-mXwfLJdaADqWg1J5+Z0bGQEdcXSe+ePPTfzffMB29aVls5cXveRl0vneSV/19t3SfuUBsAraLP8W/g5u9cmYXA== + table@^6.0.9: version "6.7.1" resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2"