diff options
| author | Arpit Chakladar <54011232+arpitchakladar@users.noreply.github.com> | 2023-02-09 13:50:24 +0530 |
|---|---|---|
| committer | Arpit Chakladar <54011232+arpitchakladar@users.noreply.github.com> | 2023-02-09 13:50:24 +0530 |
| commit | 0404234c26f6813025e9eedd9981e1536db28b2a (patch) | |
| tree | 204e2ca55540e594e4d88eba87191b90794ddaf8 | |
| parent | 915947e3e7ab7c1fa07596ab4b13bf6e1cc50b76 (diff) | |
| download | banglar-bhumi-utils-0404234c26f6813025e9eedd9981e1536db28b2a.tar.gz banglar-bhumi-utils-0404234c26f6813025e9eedd9981e1536db28b2a.zip | |
Combined the scripts with the same runtime into a single file to improve performance
| -rw-r--r-- | config/webpack.config.js | 65 | ||||
| -rw-r--r-- | config/webpack/loaders/scoped-loader.js | 15 | ||||
| -rw-r--r-- | config/webpack/plugins/create-manifest-webpack-plugin/index.js | 36 | ||||
| -rw-r--r-- | config/webpack/plugins/inject-script-webpack-plugin.js | 71 | ||||
| -rw-r--r-- | config/webpack/utils/generate-script-build-config.js | 64 | ||||
| -rw-r--r-- | config/webpack/utils/inline-javascript.js | 5 | ||||
| -rw-r--r-- | config/webpack/utils/script-runtime.js | 15 |
7 files changed, 147 insertions, 124 deletions
diff --git a/config/webpack.config.js b/config/webpack.config.js index 3f09a5a..b4cd6cd 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -5,16 +5,71 @@ process.env.ROOT_DIR = path.resolve(__dirname, ".."); process.env.CONFIG_DIR = path.resolve(process.env.ROOT_DIR, "config"); process.env.SOURCE_DIR = path.resolve(process.env.ROOT_DIR, "src"); -const CreateManifestPlugin = require("./webpack/plugins/create-manifest-webpack-plugin"); -const generateScriptBuildConfig = require("./webpack/utils/generate-script-build-config"); -const inlineJavascript = require("./webpack/utils/inline-javascript"); +const CreateManifestPlugin = require(path.resolve(process.env.CONFIG_DIR, "webpack/plugins/create-manifest-webpack-plugin")); +const SanitizeScriptsImportPlugin = require(path.resolve(process.env.CONFIG_DIR, "webpack/plugins/sanitize-scripts-import-webpack-plugin")); +const InjectScriptPlugin = require(path.resolve(process.env.CONFIG_DIR, "webpack/plugins/inject-script-webpack-plugin")); +const { inlineJavascript } = require(path.resolve(process.env.CONFIG_DIR, "webpack/utils/inline-javascript")); +const { getScriptRuntimeFromType } = require(path.resolve(process.env.CONFIG_DIR, "webpack/utils/script-runtime")); const scripts = require(path.resolve(process.env.SOURCE_DIR, "scripts.json")); let scriptBuildConfigs = []; -for (const scriptType in scripts) { - scriptBuildConfigs.push(generateScriptBuildConfig(scriptType)); +let injectedScriptsCount = 0; + +const allScripts = { + document_start: { + ...(scripts.before || {}), + ...(scripts.injected || {}), + ...(scripts.injected_and_loaded || {}) + }, + document_end: scripts.rendered, + document_idle: scripts.loaded +}; + +for (const scriptRuntime in allScripts) { + if (allScripts[scriptRuntime]) { + const importStatements = Object.keys(allScripts[scriptRuntime]).map(script => + `import "${path.resolve(process.env.SOURCE_DIR, "scripts", script)}";` + ).join("\n"); + + scriptBuildConfigs.push({ + entry: inlineJavascript(importStatements), + name: scriptRuntime, + mode: "production", + output: { + filename: `${scriptRuntime}.js` + }, + resolve: { + extensions: ["", ".ts", ".js"], + alias: { + "@": process.env.SOURCE_DIR + } + }, + module: { + rules: [ + { + test: /\.tsx?$/, + loader: "ts-loader", + options: { + configFile: "config/tsconfig.json" + } + }, + { + test: new RegExp(`^${path.resolve(process.env.SOURCE_DIR, "scripts")}`), + loader: path.resolve(process.env.CONFIG_DIR, "webpack/loaders/scoped-loader") + } + ] + }, + plugins: [ + new SanitizeScriptsImportPlugin() + ].concat( + scriptRuntime === "document_start" + ? [new InjectScriptPlugin()] + : [] + ) + }); + } } scriptBuildConfigs.push({ diff --git a/config/webpack/loaders/scoped-loader.js b/config/webpack/loaders/scoped-loader.js index 3b68ba6..1be58a4 100644 --- a/config/webpack/loaders/scoped-loader.js +++ b/config/webpack/loaders/scoped-loader.js @@ -1,5 +1,18 @@ const path = require("path"); +const scripts = require(path.resolve(process.env.SOURCE_DIR, "scripts.json")); + +const getScriptType = scriptName => { + for (const scriptType in scripts) { + if (scripts[scriptType][scriptName]) { + return scriptType; + } + } + return "undefined_script"; +}; + module.exports = function (source) { - return `/**\t${path.basename(this.resourcePath)}\t**/\n(() => {\n${source}\n})();` + return `/*<--\t${getScriptType(path.basename(this.resourcePath))}\t-->*/ +(() => {\n${source}\n})(); +/*<---->*/` }; diff --git a/config/webpack/plugins/create-manifest-webpack-plugin/index.js b/config/webpack/plugins/create-manifest-webpack-plugin/index.js index 6bbb485..7748cd9 100644 --- a/config/webpack/plugins/create-manifest-webpack-plugin/index.js +++ b/config/webpack/plugins/create-manifest-webpack-plugin/index.js @@ -2,32 +2,16 @@ const { sources } = require("webpack"); const path = require("path"); const { version } = require(path.resolve(process.env.ROOT_DIR, "package.json")); - -const getRunAt = scriptType => { - switch (scriptType) { - case "before": - case "injected": - case "injected_and_loaded": - return "document_start"; - - case "rendered": - return "document_end"; - - case "loaded": - default: - return "document_idle"; - } -}; +const { getScriptRuntimeFromType } = require(path.resolve(process.env.CONFIG_DIR, "webpack/utils/script-runtime")); class CreateManifestPlugin { constructor({ scripts }) { this.scripts = {}; this.manifest = require("./manifest-template.json"); - this.scripts.before = scripts.before || {}; - this.scripts.injected = scripts.injected || {}; - this.scripts.injected_and_loaded = scripts.injected_and_loaded || {}; - this.scripts.rendered = scripts.rendered || {}; - this.scripts.loaded = scripts.loaded || {}; + for (const scriptType in scripts) { + const scriptRuntime = getScriptRuntimeFromType(scriptType); + this.scripts[scriptRuntime] = { ...this.scripts[scriptRuntime], ...scripts[scriptType] }; + } } apply(compiler) { @@ -42,9 +26,9 @@ class CreateManifestPlugin { this.manifest.version = version; this.manifest.content_scripts = [] - for (const scriptType in this.scripts) { - if (Object.keys(this.scripts[scriptType]).length > 0) { - const currentScripts = this.scripts[scriptType]; + for (const scriptRuntime in this.scripts) { + if (Object.keys(this.scripts[scriptRuntime]).length > 0) { + const currentScripts = this.scripts[scriptRuntime]; let paths = {}; for (const scriptName in currentScripts) { @@ -58,8 +42,8 @@ class CreateManifestPlugin { for (const scriptPath in paths) { this.manifest.content_scripts.push({ matches: [`*://banglarbhumi.gov.in/${scriptPath}`], - js: [`${scriptType}.js`], - run_at: getRunAt(scriptType) + js: [`${scriptRuntime}.js`], + run_at: scriptRuntime }); } } diff --git a/config/webpack/plugins/inject-script-webpack-plugin.js b/config/webpack/plugins/inject-script-webpack-plugin.js index 213e691..592751d 100644 --- a/config/webpack/plugins/inject-script-webpack-plugin.js +++ b/config/webpack/plugins/inject-script-webpack-plugin.js @@ -1,12 +1,13 @@ const { sources } = require("webpack"); const terser = require("terser"); -class InjectScriptPlugin { - constructor({ onload, isFirst }) { - this.onload = !!onload; - this.isFirst = !!isFirst; - } +const getScriptCodeScoped = (scriptCode, loaded) => scriptCode + ? (loaded + ? `document.addEventListener(\"DOMContentLoaded\", () => {${scriptCode}});` + : `(() => {${scriptCode}})();`) + : ""; +class InjectScriptPlugin { apply(compiler) { compiler.hooks.compilation.tap("InjectScriptPlugin", compilation => { compilation.hooks.processAssets.tapPromise( @@ -18,32 +19,54 @@ class InjectScriptPlugin { async assets => { for (const assetName in assets) { if (assetName.endsWith(".js")) { - let currentAssetContent = compilation.getAsset(assetName).source.source(); - let start = `(() => { - const o = new MutationObserver(() => { - const s = document.querySelector("head > script:nth-child(54)"); - if (s) { - s.innerHTML - `; - let end = ""; - if (!this.isFirst) { - start += "+"; + let scriptEnd = 0; + const currentAssetContent = compilation.getAsset(assetName).source.source(); + const scripts = { + before: "", + injected: "", + injected_and_loaded: "" + }; + while (true) { + const start = currentAssetContent.indexOf("/*<--\t", scriptEnd + 1); + if (start < 0) { + break; + } else { + const end = currentAssetContent.indexOf("\t-->*/", start + 1); + if (end < 0) { + throw Error("Failed to parse some scripts"); + } else { + const scriptType = currentAssetContent.substring(start + 6, end); + scriptEnd = currentAssetContent.indexOf("\n/*<---->*/", end + 1) + if (scriptEnd < 0) { + break; + } + scripts[scriptType.trim()] += currentAssetContent.substring(end + 6, scriptEnd); + scriptEnd += 11; + } + } } - start += "= `"; - if (this.onload) { - start += "document.addEventListener(\"DOMContentLoaded\", () => {"; - end += "});"; + for (const scriptType in scripts) { + const currentScriptCode = (await terser.minify(scripts[scriptType].replaceAll("`", "\\`"))).code; + scripts[scriptType] = currentScriptCode + ? (scriptType === "injected_and_loaded" + ? `document.addEventListener(\"DOMContentLoaded\", () => {${currentScriptCode}});` + : `(() => {${currentScriptCode}})();`) + : ""; } - end += `\`; + const injectedCode = (scripts.injected || scripts.injected_and_loaded) + ? `const o = new MutationObserver(() => { + const s = document.querySelector("head > script:nth-child(54)"); + if (s) { + s.innerHTML = \`${scripts.injected}${scripts.injected_and_loaded}\`; o.disconnect(); } }); - o.observe(document, {childList: true, subtree: true}); - })();`; - const content = (await terser.minify(currentAssetContent.replaceAll("`", "\\`"))).code; + o.observe(document, {childList: true, subtree: true});` + : ""; + const resultantCode = scripts.before + injectedCode; compilation.updateAsset( assetName, - new sources.RawSource(start + content + end) + new sources.RawSource(resultantCode) ); } } diff --git a/config/webpack/utils/generate-script-build-config.js b/config/webpack/utils/generate-script-build-config.js deleted file mode 100644 index a6f9f54..0000000 --- a/config/webpack/utils/generate-script-build-config.js +++ /dev/null @@ -1,64 +0,0 @@ -const fs = require("fs"); -const path = require("path"); - -const SanitizeScriptsImportPlugin = require("../plugins/sanitize-scripts-import-webpack-plugin"); -const InjectScriptPlugin = require("../plugins/inject-script-webpack-plugin"); -const inlineJavascript = require("./inline-javascript"); - -const scripts = require(path.resolve(process.env.SOURCE_DIR, "scripts.json")); - -const getImportStatementForScript = script => { - const importPath = path.resolve(process.env.SOURCE_DIR, "scripts", script); - return `import "${importPath}";`; -}; - -const getVirtualEntry = scriptType => { - const importStatements = Object.keys(scripts[scriptType]).map(getImportStatementForScript).join("\n"); - - return inlineJavascript(importStatements); -} - -let injectedScriptsCount = 0; -const generateScriptBuildConfig = scriptType => { - return { - entry: getVirtualEntry(scriptType), - name: scriptType, - mode: "production", - output: { - filename: `${scriptType}.js` - }, - resolve: { - extensions: ["", ".ts", ".js"], - alias: { - "@": process.env.SOURCE_DIR - } - }, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: "ts-loader", - options: { - configFile: "config/tsconfig.json" - } - }, - { - test: new RegExp(`^${path.resolve(process.env.SOURCE_DIR, "scripts")}`), - loader: path.resolve(process.env.CONFIG_DIR, "webpack/loaders/scoped-loader") - } - ] - }, - plugins: [ - new SanitizeScriptsImportPlugin() - ].concat( - scriptType.startsWith("injected") - ? [new InjectScriptPlugin({ - onload: scriptType === "injected_and_loaded", - isFirst: injectedScriptsCount++ <= 0 - })] - : [] - ) - }; -}; - -module.exports = generateScriptBuildConfig; diff --git a/config/webpack/utils/inline-javascript.js b/config/webpack/utils/inline-javascript.js index b9348cc..ea344a4 100644 --- a/config/webpack/utils/inline-javascript.js +++ b/config/webpack/utils/inline-javascript.js @@ -1,4 +1 @@ -module.exports = code => { - const base64 = Buffer.from(code).toString("base64"); - return `data:text/javascript;base64,${base64}`; -}; +module.exports.inlineJavascript = code => `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`; diff --git a/config/webpack/utils/script-runtime.js b/config/webpack/utils/script-runtime.js new file mode 100644 index 0000000..394e87e --- /dev/null +++ b/config/webpack/utils/script-runtime.js @@ -0,0 +1,15 @@ +module.exports.getScriptRuntimeFromType = scriptType => { + switch (scriptType) { + case "before": + case "injected": + case "injected_and_loaded": + return "document_start"; + + case "rendered": + return "document_end"; + + case "loaded": + default: + return "document_idle"; + } +}; |
