From 068a14ffa464d6cb0ccc5c3cec11d10d8cceae90 Mon Sep 17 00:00:00 2001 From: Arpit Chakladar <54011232+arpitchakladar@users.noreply.github.com> Date: Sun, 26 Mar 2023 22:39:07 +0530 Subject: Sharing code between scripts for reduced bundle size. --- config/tsconfig.json | 4 +- config/webpack.config.js | 88 ++++++++++++++++------ .../create-manifest-webpack-plugin/index.js | 12 ++- config/webpack/utils/format-scripts.js | 15 ---- config/webpack/utils/get-injection-code.js | 12 +-- config/webpack/utils/scripts.js | 16 ++++ config/webpack/utils/shared-modules.js | 8 ++ src/scripts/functionality/home-page-banner.ts | 2 +- src/scripts/optimize.ts | 2 +- src/shared/modify-dom.ts | 41 ++++++++++ src/shared/observe-dom.ts | 12 +++ src/shared/styling.ts | 8 ++ src/utils/modify-dom.ts | 41 ---------- src/utils/observe-dom.ts | 12 --- src/utils/styling.ts | 8 -- 15 files changed, 163 insertions(+), 118 deletions(-) delete mode 100644 config/webpack/utils/format-scripts.js create mode 100644 config/webpack/utils/scripts.js create mode 100644 config/webpack/utils/shared-modules.js create mode 100644 src/shared/modify-dom.ts create mode 100644 src/shared/observe-dom.ts create mode 100644 src/shared/styling.ts delete mode 100644 src/utils/modify-dom.ts delete mode 100644 src/utils/observe-dom.ts delete mode 100644 src/utils/styling.ts diff --git a/config/tsconfig.json b/config/tsconfig.json index 7b1d1ef..5a41ca2 100644 --- a/config/tsconfig.json +++ b/config/tsconfig.json @@ -5,7 +5,7 @@ "strict": true, "noImplicitReturns": true, "noImplicitAny": true, - "module": "es6", + "module": "es2022", "moduleResolution": "node", "target": "es2021", "allowJs": true, @@ -14,7 +14,7 @@ "moduleDetection": "force", "baseUrl": "../", "paths": { - "@/*": ["src/*"] + "/shared/*": ["src/shared/*"] } }, "exclude": [ diff --git a/config/webpack.config.js b/config/webpack.config.js index 31d838e..baadc51 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -1,4 +1,5 @@ const path = require("path"); +const fs = require("fs"); const CopyPlugin = require("copy-webpack-plugin"); global.ROOT_DIR = path.resolve(__dirname, ".."); @@ -13,57 +14,96 @@ const InjectScriptPlugin = webpackRequire("plugins/inject-script-webpack-plugin" const { inlineJavascript } = webpackRequire("utils/inline-javascript"); const { getScriptRuntimeFromType } = webpackRequire("utils/script-runtime"); const { getFileNameHash } = webpackRequire("utils/file-name-hash"); -const { formatScripts } = webpackRequire("utils/format-scripts"); -const scripts = formatScripts(require(path.resolve(SOURCE_DIR, "scripts.json"))); +const scripts = webpackRequire("utils/scripts"); -const entries = {}; +const sharedModules = webpackRequire("utils/shared-modules"); + +const uninjectedScriptEntries = {}; +const injectedScriptEntries = {}; +const sharedModuleEntries = {}; +const sharedModuleExternals = {}; for (const scriptPath in scripts) { for (const scriptType in scripts[scriptPath]) { const currentScripts = scripts[scriptPath][scriptType]; - entries[`${scriptType} - "${scriptPath}"`] = { + const scriptEntries = scriptType.startsWith("injected") ? injectedScriptEntries : uninjectedScriptEntries; + + scriptEntries[`${scriptType} - "${scriptPath}"`] = { import: inlineJavascript(currentScripts.map(script => `import "${path.resolve(SOURCE_DIR, "scripts", script)}";`).join("\n")), filename: `scripts/${getFileNameHash(scriptPath)}-${scriptType}.js` }; } } -module.exports = { - entry: entries, +for (const sharedModule of sharedModules) { + sharedModuleEntries[sharedModule] = { + import: path.resolve(SOURCE_DIR, "shared", sharedModule), + filename: `shared/${sharedModule}.js`, + library: { + type: "module" + } + }; + sharedModuleExternals[`/shared/${sharedModule}`] = `/shared/${sharedModule}.js`; +} + +const common = { mode: "production", resolve: { - extensions: ["", ".ts", ".js"], + extensions: [".ts", ".js"], alias: { - "@": global.SOURCE_DIR + "/shared": path.resolve(global.SOURCE_DIR, "shared") } }, module: { rules: [ { - test: /\.tsx?$/, + test: /\.ts$/, loader: "ts-loader", options: { configFile: "config/tsconfig.json" } - }, - { - test: /\.(jpg|png|gif)$/, - loader: "url-loader" } ] }, optimization: { minimize: process.env.NODE_ENV === "production" - }, - plugins: [ - new InjectScriptPlugin(), - new CopyPlugin({ - patterns: [{ - from: path.resolve(ROOT_DIR, "static"), - to: "./" - }] - }), - new CreateManifestPlugin() - ] + } }; + +module.exports = [ + { + ...common, + experiments: { + outputModule: true, + topLevelAwait: true + }, + externals: sharedModuleExternals, + entry: uninjectedScriptEntries, + plugins: [ + new CopyPlugin({ + patterns: [{ + from: path.resolve(ROOT_DIR, "static"), + to: "./" + }] + }), + new CreateManifestPlugin() + ] + }, + { + ...common, + entry: injectedScriptEntries, + plugins: [ + new InjectScriptPlugin(), + ] + }, + { + ...common, + externals: sharedModuleExternals, + experiments: { + outputModule: true, + topLevelAwait: true + }, + entry: sharedModuleEntries + } +]; diff --git a/config/webpack/plugins/create-manifest-webpack-plugin/index.js b/config/webpack/plugins/create-manifest-webpack-plugin/index.js index 1940c6e..77f5959 100644 --- a/config/webpack/plugins/create-manifest-webpack-plugin/index.js +++ b/config/webpack/plugins/create-manifest-webpack-plugin/index.js @@ -3,7 +3,9 @@ const path = require("path"); const { getScriptRuntimeFromType } = webpackRequire("utils/script-runtime"); const { getFileNameHash } = webpackRequire("utils/file-name-hash"); -const { formatScripts } = webpackRequire("utils/format-scripts"); +const scripts = webpackRequire("utils/scripts"); +const sharedModules = webpackRequire("utils/shared-modules"); +const manifest = webpackRequire("plugins/create-manifest-webpack-plugin/manifest-template.json"); class CreateManifestPlugin { apply(compiler) { @@ -15,8 +17,6 @@ class CreateManifestPlugin { additionalAssets: true }, assets => { - const scripts = formatScripts(require(path.resolve(SOURCE_DIR, "scripts.json"))); - const manifest = webpackRequire("plugins/create-manifest-webpack-plugin/manifest-template.json"); manifest.version = require(path.resolve(ROOT_DIR, "package.json")).version; manifest.content_scripts = []; @@ -37,9 +37,13 @@ class CreateManifestPlugin { const resources = []; - for (const assetName in assets) + for (const assetName in assets) { if (/^assets\/.*\.(jpg|png|gif)$/.test(assetName)) resources.push(assetName); + } + + for (const sharedModule of sharedModules) + resources.push(`shared/${sharedModule}.js`); if (resources.length > 0) { manifest.web_accessible_resources = [ diff --git a/config/webpack/utils/format-scripts.js b/config/webpack/utils/format-scripts.js deleted file mode 100644 index 0961674..0000000 --- a/config/webpack/utils/format-scripts.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports.formatScripts = scripts => { - const _scripts = {}; - - for (const scriptType in scripts) { - const currentScripts = scripts[scriptType]; - for (const scriptName in currentScripts) { - const scriptPath = currentScripts[scriptName]; - _scripts[scriptPath] = _scripts[scriptPath] || {}; - _scripts[scriptPath][scriptType] = _scripts[scriptPath][scriptType] || []; - _scripts[scriptPath][scriptType].push(scriptName); - } - } - - return _scripts; -}; diff --git a/config/webpack/utils/get-injection-code.js b/config/webpack/utils/get-injection-code.js index 51d1c20..6333a6a 100644 --- a/config/webpack/utils/get-injection-code.js +++ b/config/webpack/utils/get-injection-code.js @@ -1,18 +1,10 @@ module.exports.getInjectionCode = (code, front) => { - const escapeSequences = [ - ["\b", "\\b"], - ["\f", "\\f"], - ["\n", "\\n"], - ["\r", "\\r"], - ["\t", "\\t"], - ["\v", "\\v"] - ]; + const escapeSequences = ["b", "f", "n", "r", "t", "v"]; let finalCode = code.replaceAll("`","\\`"); for (const escapeSequence of escapeSequences) { finalCode = finalCode - .replaceAll(escapeSequence[1], "\\" + escapeSequence[1]) - .replaceAll(escapeSequence[0], escapeSequence[1]); + .replaceAll("\\" + escapeSequence, "\\\\" + escapeSequence) } const concatenationCode = front diff --git a/config/webpack/utils/scripts.js b/config/webpack/utils/scripts.js new file mode 100644 index 0000000..2196737 --- /dev/null +++ b/config/webpack/utils/scripts.js @@ -0,0 +1,16 @@ +const path = require("path"); +const scripts = require(path.resolve(SOURCE_DIR, "scripts.json")); + +const formattedScripts = {}; + +for (const scriptType in scripts) { + const currentScripts = scripts[scriptType]; + for (const scriptName in currentScripts) { + const scriptPath = currentScripts[scriptName]; + formattedScripts[scriptPath] = formattedScripts[scriptPath] || {}; + formattedScripts[scriptPath][scriptType] = formattedScripts[scriptPath][scriptType] || []; + formattedScripts[scriptPath][scriptType].push(scriptName); + } +} + +module.exports = formattedScripts; diff --git a/config/webpack/utils/shared-modules.js b/config/webpack/utils/shared-modules.js new file mode 100644 index 0000000..f10d4a1 --- /dev/null +++ b/config/webpack/utils/shared-modules.js @@ -0,0 +1,8 @@ +const path = require("path"); +const fs = require("fs"); + +const sharedModules = fs.readdirSync(path.resolve(SOURCE_DIR, "shared")) + .filter(sharedModule => !sharedModule.endsWith("import-shared.js")) + .map(sharedModule => sharedModule.substring(0, sharedModule.length - 3));4 + +module.exports = sharedModules; diff --git a/src/scripts/functionality/home-page-banner.ts b/src/scripts/functionality/home-page-banner.ts index 249b361..75069ca 100644 --- a/src/scripts/functionality/home-page-banner.ts +++ b/src/scripts/functionality/home-page-banner.ts @@ -1,4 +1,4 @@ -import { styles } from "@/utils/styling"; +const { styles } = await import(/* webpackIgnore: true */ "/shared/styling.js"); styles("#slider", { overflow: "visible", diff --git a/src/scripts/optimize.ts b/src/scripts/optimize.ts index 8389c53..93dd0e2 100644 --- a/src/scripts/optimize.ts +++ b/src/scripts/optimize.ts @@ -1,4 +1,4 @@ -import { modifyDOM } from "@/utils/modify-dom"; +const { modifyDOM } = await import(/* webpackIgnore: true */ "/shared/modify-dom.js"); modifyDOM([ ["head > script:nth-child(34)", { src: null }], diff --git a/src/shared/modify-dom.ts b/src/shared/modify-dom.ts new file mode 100644 index 0000000..0832d5b --- /dev/null +++ b/src/shared/modify-dom.ts @@ -0,0 +1,41 @@ +import { observeDOM } from "/shared/observe-dom"; + +type DOMReplacements = { + innerHTML?: string; + [key: string]: string | undefined | null; +}; + +type DOMModificaitonRule = readonly [string, DOMReplacements]; + +export const modifyDOM = (modificationRules: (DOMModificaitonRule | null)[]) => { + let count = 0; + + observeDOM(() => { + for (let i = 0; i < modificationRules.length; i++) { + if (modificationRules[i]) { + const element = document.querySelector(modificationRules[i]![0]) as HTMLElement | null; + if (element) { + const attributes = modificationRules[i]![1] as DOMReplacements; + if (attributes.innerHTML) { + element.innerHTML = attributes.innerHTML as string; + } + delete attributes.innerHTML; + for (const attribute in attributes) { + if (attributes[attribute] === null) { + element.removeAttribute(attribute); + } else { + element.setAttribute(attribute, attributes[attribute] as string); + } + } + modificationRules[i] = null; + count++; + if (count >= modificationRules.length) { + return true; + } + } + } + } + + return false; + }); +}; diff --git a/src/shared/observe-dom.ts b/src/shared/observe-dom.ts new file mode 100644 index 0000000..4a447a0 --- /dev/null +++ b/src/shared/observe-dom.ts @@ -0,0 +1,12 @@ +export const observeDOM = (callback: () => boolean) => { + const observer = new MutationObserver(() => { + if (callback()) { + observer.disconnect(); + } + }); + + observer.observe(document, { + childList: true, + subtree: true + }); +}; diff --git a/src/shared/styling.ts b/src/shared/styling.ts new file mode 100644 index 0000000..0e527d9 --- /dev/null +++ b/src/shared/styling.ts @@ -0,0 +1,8 @@ +export const styles = (selector: string, styles: { [key: string]: string }) => { + const elements = Array.from(document.querySelectorAll(selector)) as HTMLElement[]; + for (const element of elements) { + for (const styleType in styles) { + element.style[styleType as any] = styles[styleType]; + } + } +}; diff --git a/src/utils/modify-dom.ts b/src/utils/modify-dom.ts deleted file mode 100644 index f08f7d9..0000000 --- a/src/utils/modify-dom.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { observeDOM } from "@/utils/observe-dom"; - -type DOMReplacements = { - innerHTML?: string; - [key: string]: string | undefined | null; -}; - -type DOMModificaitonRule = readonly [string, DOMReplacements]; - -export const modifyDOM = (modificationRules: (DOMModificaitonRule | null)[]) => { - let count = 0; - - observeDOM(() => { - for (let i = 0; i < modificationRules.length; i++) { - if (modificationRules[i]) { - const element = document.querySelector(modificationRules[i]![0]) as HTMLElement | null; - if (element) { - const attributes = modificationRules[i]![1] as DOMReplacements; - if (attributes.innerHTML) { - element.innerHTML = attributes.innerHTML as string; - } - delete attributes.innerHTML; - for (const attribute in attributes) { - if (attributes[attribute] === null) { - element.removeAttribute(attribute); - } else { - element.setAttribute(attribute, attributes[attribute] as string); - } - } - modificationRules[i] = null; - count++; - if (count >= modificationRules.length) { - return true; - } - } - } - } - - return false; - }); -}; diff --git a/src/utils/observe-dom.ts b/src/utils/observe-dom.ts deleted file mode 100644 index 4a447a0..0000000 --- a/src/utils/observe-dom.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const observeDOM = (callback: () => boolean) => { - const observer = new MutationObserver(() => { - if (callback()) { - observer.disconnect(); - } - }); - - observer.observe(document, { - childList: true, - subtree: true - }); -}; diff --git a/src/utils/styling.ts b/src/utils/styling.ts deleted file mode 100644 index 0e527d9..0000000 --- a/src/utils/styling.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const styles = (selector: string, styles: { [key: string]: string }) => { - const elements = Array.from(document.querySelectorAll(selector)) as HTMLElement[]; - for (const element of elements) { - for (const styleType in styles) { - element.style[styleType as any] = styles[styleType]; - } - } -}; -- cgit v1.2.3