From b2b46932e9eb2283836aa66f931ca44096883684 Mon Sep 17 00:00:00 2001 From: Lalle <29478339+LalleSX@users.noreply.github.com> Date: Sat, 1 Apr 2023 01:54:44 +0200 Subject: [PATCH] Big bang --- nodemon.json | 13 ++++++++ package.json | 44 +++++++++++++++++++++++++ postcss.config.cjs | 6 ++++ public/icon-128.png | Bin 0 -> 19200 bytes public/icon-34.png | Bin 0 -> 2808 bytes src/assets/img/logo.svg | 7 ++++ src/assets/styles/tailwind.css | 3 ++ src/global.d.ts | 21 ++++++++++++ src/manifest.ts | 42 ++++++++++++++++++++++++ src/pages/background/index.ts | 1 + src/pages/content/index.ts | 5 +++ src/pages/content/style.css | 0 src/pages/devtools/index.html | 10 ++++++ src/pages/devtools/index.ts | 7 ++++ src/pages/newtab/Newtab.css | 38 ++++++++++++++++++++++ src/pages/newtab/Newtab.tsx | 24 ++++++++++++++ src/pages/newtab/index.css | 13 ++++++++ src/pages/newtab/index.html | 12 +++++++ src/pages/newtab/index.tsx | 13 ++++++++ src/pages/options/Options.css | 8 +++++ src/pages/options/Options.tsx | 6 ++++ src/pages/options/index.css | 0 src/pages/options/index.html | 12 +++++++ src/pages/options/index.tsx | 13 ++++++++ src/pages/panel/Panel.css | 7 ++++ src/pages/panel/Panel.tsx | 10 ++++++ src/pages/panel/index.css | 0 src/pages/panel/index.html | 12 +++++++ src/pages/panel/index.tsx | 13 ++++++++ src/pages/popup/Popup.tsx | 24 ++++++++++++++ src/pages/popup/index.css | 12 +++++++ src/pages/popup/index.html | 12 +++++++ src/pages/popup/index.tsx | 14 ++++++++ src/vite-env.d.ts | 1 + tailwind.config.cjs | 11 +++++++ tsconfig.json | 27 ++++++++++++++++ utils/log.ts | 48 ++++++++++++++++++++++++++++ utils/plugins/copy-content-style.ts | 21 ++++++++++++ utils/plugins/make-manifest.ts | 26 +++++++++++++++ vite.config.ts | 41 ++++++++++++++++++++++++ 40 files changed, 577 insertions(+) create mode 100644 nodemon.json create mode 100755 package.json create mode 100644 postcss.config.cjs create mode 100644 public/icon-128.png create mode 100644 public/icon-34.png create mode 100644 src/assets/img/logo.svg create mode 100644 src/assets/styles/tailwind.css create mode 100644 src/global.d.ts create mode 100755 src/manifest.ts create mode 100644 src/pages/background/index.ts create mode 100644 src/pages/content/index.ts create mode 100644 src/pages/content/style.css create mode 100644 src/pages/devtools/index.html create mode 100644 src/pages/devtools/index.ts create mode 100644 src/pages/newtab/Newtab.css create mode 100644 src/pages/newtab/Newtab.tsx create mode 100644 src/pages/newtab/index.css create mode 100644 src/pages/newtab/index.html create mode 100644 src/pages/newtab/index.tsx create mode 100644 src/pages/options/Options.css create mode 100644 src/pages/options/Options.tsx create mode 100644 src/pages/options/index.css create mode 100644 src/pages/options/index.html create mode 100644 src/pages/options/index.tsx create mode 100644 src/pages/panel/Panel.css create mode 100644 src/pages/panel/Panel.tsx create mode 100644 src/pages/panel/index.css create mode 100644 src/pages/panel/index.html create mode 100644 src/pages/panel/index.tsx create mode 100644 src/pages/popup/Popup.tsx create mode 100644 src/pages/popup/index.css create mode 100644 src/pages/popup/index.html create mode 100644 src/pages/popup/index.tsx create mode 100644 src/vite-env.d.ts create mode 100644 tailwind.config.cjs create mode 100644 tsconfig.json create mode 100644 utils/log.ts create mode 100644 utils/plugins/copy-content-style.ts create mode 100644 utils/plugins/make-manifest.ts create mode 100644 vite.config.ts diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..473e05e --- /dev/null +++ b/nodemon.json @@ -0,0 +1,13 @@ +{ + "env": { + "__DEV__": "true" + }, + "watch": [ + "src", "utils", "vite.config.ts" + ], + "ext": "tsx,css,html,ts", + "ignore": [ + "src/**/*.spec.ts" + ], + "exec": "vite build" +} diff --git a/package.json b/package.json new file mode 100755 index 0000000..04aa999 --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "vite-web-extension", + "displayName": "Web Extension Boilerplate", + "version": "1.1.0", + "description": "A simple chrome extension template with Vite, React, TypeScript and Tailwind CSS.", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/JohnBra/web-extension.git" + }, + "scripts": { + "build": "vite build", + "dev": "nodemon" + }, + "type": "module", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "webextension-polyfill": "^0.10.0" + }, + "devDependencies": { + "@types/node": "^18.11.18", + "@types/react": "^18.0.27", + "@types/react-dom": "^18.0.10", + "@types/webextension-polyfill": "^0.10.0", + "@typescript-eslint/eslint-plugin": "^5.49.0", + "@typescript-eslint/parser": "^5.49.0", + "@vitejs/plugin-react-swc": "^3.0.1", + "autoprefixer": "^10.4.13", + "eslint": "^8.32.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.32.1", + "eslint-plugin-react-hooks": "^4.3.0", + "fs-extra": "^11.1.0", + "nodemon": "^2.0.20", + "postcss": "^8.4.21", + "tailwindcss": "^3.2.4", + "ts-node": "^10.9.1", + "typescript": "^4.9.4", + "vite": "^4.0.4" + } +} diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/public/icon-128.png b/public/icon-128.png new file mode 100644 index 0000000000000000000000000000000000000000..15bd934a116284162e96fa6397b606f531338a02 GIT binary patch literal 19200 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 + + + + + + diff --git a/src/assets/styles/tailwind.css b/src/assets/styles/tailwind.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/src/assets/styles/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..55db9b8 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,21 @@ +declare module '*.svg' { + import React = require('react'); + export const ReactComponent: React.SFC>; + const src: string; + export default src; +} + +declare module '*.jpg' { + const content: string; + export default content; +} + +declare module '*.png' { + const content: string; + export default content; +} + +declare module '*.json' { + const content: string; + export default content; +} diff --git a/src/manifest.ts b/src/manifest.ts new file mode 100755 index 0000000..39fe016 --- /dev/null +++ b/src/manifest.ts @@ -0,0 +1,42 @@ +import type { Manifest } from 'webextension-polyfill'; +import pkg from '../package.json'; + +const manifest: Manifest.WebExtensionManifest = { + manifest_version: 3, + name: pkg.displayName, + version: pkg.version, + description: pkg.description, + options_ui: { + page: 'src/pages/options/index.html', + }, + background: { + service_worker: 'src/pages/background/index.js', + type: 'module', + }, + action: { + default_popup: 'src/pages/popup/index.html', + default_icon: 'icon-34.png', + }, + chrome_url_overrides: { + newtab: 'src/pages/newtab/index.html', + }, + icons: { + '128': 'icon-128.png', + }, + content_scripts: [ + { + matches: ['http://*/*', 'https://*/*', ''], + js: ['src/pages/content/index.js'], + css: ['contentStyle.css'], + }, + ], + devtools_page: 'src/pages/devtools/index.html', + web_accessible_resources: [ + { + resources: ['contentStyle.css', 'icon-128.png', 'icon-34.png'], + matches: [], + }, + ], +}; + +export default manifest; diff --git a/src/pages/background/index.ts b/src/pages/background/index.ts new file mode 100644 index 0000000..def0db5 --- /dev/null +++ b/src/pages/background/index.ts @@ -0,0 +1 @@ +console.log('background script loaded'); diff --git a/src/pages/content/index.ts b/src/pages/content/index.ts new file mode 100644 index 0000000..55c69a9 --- /dev/null +++ b/src/pages/content/index.ts @@ -0,0 +1,5 @@ +try { + console.log('content script loaded'); +} catch (e) { + console.error(e); +} diff --git a/src/pages/content/style.css b/src/pages/content/style.css new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/devtools/index.html b/src/pages/devtools/index.html new file mode 100644 index 0000000..e17e5b9 --- /dev/null +++ b/src/pages/devtools/index.html @@ -0,0 +1,10 @@ + + + + + Devtools + + + + + diff --git a/src/pages/devtools/index.ts b/src/pages/devtools/index.ts new file mode 100644 index 0000000..f280e52 --- /dev/null +++ b/src/pages/devtools/index.ts @@ -0,0 +1,7 @@ +import Browser from 'webextension-polyfill'; + +Browser + .devtools + .panels + .create('Dev Tools', 'icon-34.png', 'src/pages/panel/index.html') + .catch(console.error); diff --git a/src/pages/newtab/Newtab.css b/src/pages/newtab/Newtab.css new file mode 100644 index 0000000..74b5e05 --- /dev/null +++ b/src/pages/newtab/Newtab.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/src/pages/newtab/Newtab.tsx b/src/pages/newtab/Newtab.tsx new file mode 100644 index 0000000..38ce5dc --- /dev/null +++ b/src/pages/newtab/Newtab.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import logo from '@assets/img/logo.svg'; +import '@pages/newtab/Newtab.css'; + +export default function Newtab(): JSX.Element { + return ( +
+
+ logo +

+ Edit src/pages/newtab/Newtab.tsx and save to reload. +

+ + Learn React! + +
+
+ ); +} diff --git a/src/pages/newtab/index.css b/src/pages/newtab/index.css new file mode 100644 index 0000000..ec2585e --- /dev/null +++ b/src/pages/newtab/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/src/pages/newtab/index.html b/src/pages/newtab/index.html new file mode 100644 index 0000000..7e455b9 --- /dev/null +++ b/src/pages/newtab/index.html @@ -0,0 +1,12 @@ + + + + + New tab + + + +
+ + + diff --git a/src/pages/newtab/index.tsx b/src/pages/newtab/index.tsx new file mode 100644 index 0000000..6923d34 --- /dev/null +++ b/src/pages/newtab/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import Newtab from '@pages/newtab/Newtab'; +import '@pages/newtab/index.css'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find Newtab root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/src/pages/options/Options.css b/src/pages/options/Options.css new file mode 100644 index 0000000..1ea51cb --- /dev/null +++ b/src/pages/options/Options.css @@ -0,0 +1,8 @@ +.container { + width: 100%; + height: 50vh; + font-size: 2rem; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/src/pages/options/Options.tsx b/src/pages/options/Options.tsx new file mode 100644 index 0000000..b6c79c8 --- /dev/null +++ b/src/pages/options/Options.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import '@pages/options/Options.css'; + +export default function Options(): JSX.Element { + return
Options
; +} diff --git a/src/pages/options/index.css b/src/pages/options/index.css new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/options/index.html b/src/pages/options/index.html new file mode 100644 index 0000000..fe96b7f --- /dev/null +++ b/src/pages/options/index.html @@ -0,0 +1,12 @@ + + + + + Options + + + +
+ + + diff --git a/src/pages/options/index.tsx b/src/pages/options/index.tsx new file mode 100644 index 0000000..cac9888 --- /dev/null +++ b/src/pages/options/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import Options from '@pages/options/Options'; +import '@pages/options/index.css'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find Options root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/src/pages/panel/Panel.css b/src/pages/panel/Panel.css new file mode 100644 index 0000000..843f23e --- /dev/null +++ b/src/pages/panel/Panel.css @@ -0,0 +1,7 @@ +body { + background-color: #242424; +} + +.container { + color: #ffffff; +} \ No newline at end of file diff --git a/src/pages/panel/Panel.tsx b/src/pages/panel/Panel.tsx new file mode 100644 index 0000000..44eb2ed --- /dev/null +++ b/src/pages/panel/Panel.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import '@pages/panel/Panel.css'; + +export default function Panel(): JSX.Element { + return ( +
+

Dev Tools Panel

+
+ ); +} diff --git a/src/pages/panel/index.css b/src/pages/panel/index.css new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/panel/index.html b/src/pages/panel/index.html new file mode 100644 index 0000000..564b65b --- /dev/null +++ b/src/pages/panel/index.html @@ -0,0 +1,12 @@ + + + + + Devtools Panel + + + +
+ + + diff --git a/src/pages/panel/index.tsx b/src/pages/panel/index.tsx new file mode 100644 index 0000000..84fa209 --- /dev/null +++ b/src/pages/panel/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import Panel from '@pages/panel/Panel'; +import '@pages/panel/index.css'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find Panel root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/src/pages/popup/Popup.tsx b/src/pages/popup/Popup.tsx new file mode 100644 index 0000000..94555c7 --- /dev/null +++ b/src/pages/popup/Popup.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import logo from '@assets/img/logo.svg'; + +export default function Popup(): JSX.Element { + return ( +
+
+ logo +

+ Edit src/pages/popup/Popup.jsx and save to reload. +

+ + Learn React! + +

Popup styled with TailwindCSS!

+
+
+ ); +} diff --git a/src/pages/popup/index.css b/src/pages/popup/index.css new file mode 100644 index 0000000..906301e --- /dev/null +++ b/src/pages/popup/index.css @@ -0,0 +1,12 @@ +body { + width: 300px; + height: 260px; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + position: relative; +} diff --git a/src/pages/popup/index.html b/src/pages/popup/index.html new file mode 100644 index 0000000..7b8317a --- /dev/null +++ b/src/pages/popup/index.html @@ -0,0 +1,12 @@ + + + + + Popup + + + +
+ + + diff --git a/src/pages/popup/index.tsx b/src/pages/popup/index.tsx new file mode 100644 index 0000000..c62dee0 --- /dev/null +++ b/src/pages/popup/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import '@pages/popup/index.css'; +import '@assets/styles/tailwind.css'; +import Popup from '@pages/popup/Popup'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find Popup root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tailwind.config.cjs b/tailwind.config.cjs new file mode 100644 index 0000000..8b13b45 --- /dev/null +++ b/tailwind.config.cjs @@ -0,0 +1,11 @@ +module.exports = { + content: ["./src/**/*.{js,jsx,ts,tsx}"], + theme: { + extend: { + animation: { + 'spin-slow': 'spin 20s linear infinite', + } + }, + }, + plugins: [], +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c30993f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "esnext", + "types": ["vite/client", "node"], + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "noEmit": true, + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@src/*": ["src/*"], + "@assets/*": ["src/assets/*"], + "@pages/*": ["src/pages/*"] + } + }, + "include": ["src", + "utils", "vite.config.ts"], +} diff --git a/utils/log.ts b/utils/log.ts new file mode 100644 index 0000000..6f79d20 --- /dev/null +++ b/utils/log.ts @@ -0,0 +1,48 @@ +type ColorType = 'success' | 'info' | 'error' | 'warning' | keyof typeof COLORS; + +export default function colorLog(message: string, type?: ColorType) { + let color: string = type || COLORS.FgBlack; + + switch (type) { + case 'success': + color = COLORS.FgGreen; + break; + case 'info': + color = COLORS.FgBlue; + break; + case 'error': + color = COLORS.FgRed; + break; + case 'warning': + color = COLORS.FgYellow; + break; + } + + console.log(color, message); +} + +const COLORS = { + Reset: '\x1b[0m', + Bright: '\x1b[1m', + Dim: '\x1b[2m', + Underscore: '\x1b[4m', + Blink: '\x1b[5m', + Reverse: '\x1b[7m', + Hidden: '\x1b[8m', + FgBlack: '\x1b[30m', + FgRed: '\x1b[31m', + FgGreen: '\x1b[32m', + FgYellow: '\x1b[33m', + FgBlue: '\x1b[34m', + FgMagenta: '\x1b[35m', + FgCyan: '\x1b[36m', + FgWhite: '\x1b[37m', + BgBlack: '\x1b[40m', + BgRed: '\x1b[41m', + BgGreen: '\x1b[42m', + BgYellow: '\x1b[43m', + BgBlue: '\x1b[44m', + BgMagenta: '\x1b[45m', + BgCyan: '\x1b[46m', + BgWhite: '\x1b[47m', +} as const; diff --git a/utils/plugins/copy-content-style.ts b/utils/plugins/copy-content-style.ts new file mode 100644 index 0000000..c898441 --- /dev/null +++ b/utils/plugins/copy-content-style.ts @@ -0,0 +1,21 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import colorLog from '../log'; +import { PluginOption } from 'vite'; + +const { resolve } = path; + +const root = resolve(__dirname, '..', '..'); +const contentStyle = resolve(root, 'src', 'pages', 'content', 'style.css'); +const outDir = resolve(__dirname, '..', '..', 'public'); + +export default function copyContentStyle(): PluginOption { + return { + name: 'make-manifest', + buildEnd() { + fs.copyFileSync(contentStyle, resolve(outDir, 'contentStyle.css')); + + colorLog('contentStyle copied', 'success'); + }, + }; +} diff --git a/utils/plugins/make-manifest.ts b/utils/plugins/make-manifest.ts new file mode 100644 index 0000000..ff0619a --- /dev/null +++ b/utils/plugins/make-manifest.ts @@ -0,0 +1,26 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import colorLog from '../log'; +import manifest from '../../src/manifest'; +import { PluginOption } from 'vite'; + +const { resolve } = path; + +const outDir = resolve(__dirname, '..', '..', 'public'); + +export default function makeManifest(): PluginOption { + return { + name: 'make-manifest', + buildEnd() { + if (!fs.existsSync(outDir)) { + fs.mkdirSync(outDir); + } + + const manifestPath = resolve(outDir, 'manifest.json'); + + fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); + + colorLog(`Manifest file copy complete: ${manifestPath}`, 'success'); + }, + }; +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..2784ac7 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,41 @@ +import react from '@vitejs/plugin-react-swc'; +import { resolve } from 'path'; +import { defineConfig } from 'vite'; +import copyContentStyle from './utils/plugins/copy-content-style'; +import makeManifest from './utils/plugins/make-manifest'; + +const root = resolve(__dirname, 'src'); +const pagesDir = resolve(root, 'pages'); +const assetsDir = resolve(root, 'assets'); +const outDir = resolve(__dirname, 'dist'); +const publicDir = resolve(__dirname, 'public'); + +export default defineConfig({ + resolve: { + alias: { + '@src': root, + '@assets': assetsDir, + '@pages': pagesDir, + }, + }, + plugins: [react(), makeManifest(), copyContentStyle()], + publicDir, + build: { + outDir, + sourcemap: process.env.__DEV__ === 'true', + rollupOptions: { + input: { + devtools: resolve(pagesDir, 'devtools', 'index.html'), + panel: resolve(pagesDir, 'panel', 'index.html'), + content: resolve(pagesDir, 'content', 'index.ts'), + background: resolve(pagesDir, 'background', 'index.ts'), + popup: resolve(pagesDir, 'popup', 'index.html'), + newtab: resolve(pagesDir, 'newtab', 'index.html'), + options: resolve(pagesDir, 'options', 'index.html'), + }, + output: { + entryFileNames: (chunk) => `src/pages/${chunk.name}/index.js`, + }, + }, + }, +});