@shoplflow/extension 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +201 -0
  3. package/README.md +172 -0
  4. package/dist/assets/css/contentStyle17107484687.chunk.css +1 -0
  5. package/dist/assets/css/optionsIndex.chunk.css +1 -0
  6. package/dist/assets/css/popupIndex.chunk.css +1 -0
  7. package/dist/assets/js/index.a235624f.js +1 -0
  8. package/dist/assets/js/jsx-runtime.ea866ad2.js +40 -0
  9. package/dist/assets/js/twind.60e4b726.js +1 -0
  10. package/dist/icon-128.png +0 -0
  11. package/dist/icon-34.png +0 -0
  12. package/dist/manifest.json +45 -0
  13. package/dist/src/pages/background/index.js +1 -0
  14. package/dist/src/pages/content/index.js +1 -0
  15. package/dist/src/pages/options/index.html +15 -0
  16. package/dist/src/pages/options/index.js +1 -0
  17. package/dist/src/pages/popup/index.html +16 -0
  18. package/dist/src/pages/popup/index.js +918 -0
  19. package/manifest.ts +37 -0
  20. package/package.json +57 -0
  21. package/public/icon-128.png +0 -0
  22. package/public/icon-34.png +0 -0
  23. package/public/manifest.json +45 -0
  24. package/src/Components/ElementListCard.tsx +35 -0
  25. package/src/assets/img/logo.svg +7 -0
  26. package/src/environment.d.ts +10 -0
  27. package/src/global.d.ts +37 -0
  28. package/src/pages/background/index.ts +11 -0
  29. package/src/pages/content/components/Demo/app.tsx +93 -0
  30. package/src/pages/content/components/Demo/index.tsx +27 -0
  31. package/src/pages/content/index.ts +7 -0
  32. package/src/pages/content/style.scss +7 -0
  33. package/src/pages/options/Options.css +8 -0
  34. package/src/pages/options/Options.tsx +8 -0
  35. package/src/pages/options/index.css +0 -0
  36. package/src/pages/options/index.html +12 -0
  37. package/src/pages/options/index.tsx +18 -0
  38. package/src/pages/panel/Panel.css +7 -0
  39. package/src/pages/panel/Panel.tsx +65 -0
  40. package/src/pages/panel/index.css +0 -0
  41. package/src/pages/panel/index.html +12 -0
  42. package/src/pages/panel/index.tsx +20 -0
  43. package/src/pages/popup/Popup.css +44 -0
  44. package/src/pages/popup/Popup.tsx +123 -0
  45. package/src/pages/popup/index.css +13 -0
  46. package/src/pages/popup/index.html +12 -0
  47. package/src/pages/popup/index.tsx +20 -0
  48. package/src/shared/hoc/withErrorBoundary.tsx +42 -0
  49. package/src/shared/hoc/withSuspense.tsx +14 -0
  50. package/src/shared/hooks/useStorage.tsx +47 -0
  51. package/src/shared/storages/base.ts +75 -0
  52. package/src/shared/storages/componentsInfoStorage.ts +46 -0
  53. package/src/shared/style/twind.ts +13 -0
  54. package/src/vite-env.d.ts +1 -0
  55. package/tsconfig.json +29 -0
  56. package/twind.config.ts +7 -0
  57. package/utils/checkShopl.ts +6 -0
  58. package/utils/log.ts +52 -0
  59. package/utils/manifest-parser/index.ts +35 -0
  60. package/utils/plugins/add-hmr.ts +46 -0
  61. package/utils/plugins/custom-dynamic-import.ts +34 -0
  62. package/utils/plugins/make-manifest.ts +49 -0
  63. package/utils/plugins/watch-rebuild.ts +16 -0
  64. package/utils/reload/constant.ts +5 -0
  65. package/utils/reload/initReloadClient.ts +52 -0
  66. package/utils/reload/initReloadServer.js +72 -0
  67. package/utils/reload/initReloadServer.ts +68 -0
  68. package/utils/reload/injections/script.js +60 -0
  69. package/utils/reload/injections/script.ts +12 -0
  70. package/utils/reload/injections/view.js +74 -0
  71. package/utils/reload/injections/view.ts +29 -0
  72. package/utils/reload/interpreter/index.ts +13 -0
  73. package/utils/reload/interpreter/types.ts +15 -0
  74. package/utils/reload/rollup.config.ts +28 -0
  75. package/utils/reload/utils.ts +9 -0
  76. package/vite.config.ts +89 -0
@@ -0,0 +1,16 @@
1
+ import type { PluginOption } from 'vite';
2
+ import { resolve } from 'path';
3
+
4
+ const rootDir = resolve(__dirname, '..', '..');
5
+ const manifestFile = resolve(rootDir, 'manifest.ts');
6
+ const viteConfigFile = resolve(rootDir, 'vite.config.ts');
7
+
8
+ export default function watchRebuild(): PluginOption {
9
+ return {
10
+ name: 'watch-rebuild',
11
+ buildStart() {
12
+ this.addWatchFile(manifestFile);
13
+ this.addWatchFile(viteConfigFile);
14
+ },
15
+ };
16
+ }
@@ -0,0 +1,5 @@
1
+ export const LOCAL_RELOAD_SOCKET_PORT = 8081;
2
+ export const LOCAL_RELOAD_SOCKET_URL = `ws://localhost:${LOCAL_RELOAD_SOCKET_PORT}`;
3
+ export const UPDATE_PENDING_MESSAGE = 'wait_update';
4
+ export const UPDATE_REQUEST_MESSAGE = 'do_update';
5
+ export const UPDATE_COMPLETE_MESSAGE = 'done_update';
@@ -0,0 +1,52 @@
1
+ import {
2
+ LOCAL_RELOAD_SOCKET_URL,
3
+ UPDATE_COMPLETE_MESSAGE,
4
+ UPDATE_PENDING_MESSAGE,
5
+ UPDATE_REQUEST_MESSAGE,
6
+ } from './constant';
7
+ import MessageInterpreter from './interpreter';
8
+
9
+ let needToUpdate = false;
10
+
11
+ export default function initReloadClient({
12
+ watchPath,
13
+ onUpdate,
14
+ }: {
15
+ watchPath: string;
16
+ onUpdate: () => void;
17
+ }): WebSocket {
18
+ const socket = new WebSocket(LOCAL_RELOAD_SOCKET_URL);
19
+
20
+ function sendUpdateCompleteMessage() {
21
+ socket.send(MessageInterpreter.send({ type: UPDATE_COMPLETE_MESSAGE }));
22
+ }
23
+
24
+ socket.addEventListener('message', event => {
25
+ const message = MessageInterpreter.receive(String(event.data));
26
+
27
+ switch (message.type) {
28
+ case UPDATE_REQUEST_MESSAGE: {
29
+ if (needToUpdate) {
30
+ sendUpdateCompleteMessage();
31
+ needToUpdate = false;
32
+ onUpdate();
33
+ }
34
+ return;
35
+ }
36
+ case UPDATE_PENDING_MESSAGE: {
37
+ if (!needToUpdate) {
38
+ needToUpdate = message.path.includes(watchPath);
39
+ }
40
+ return;
41
+ }
42
+ }
43
+ });
44
+
45
+ socket.onclose = () => {
46
+ console.warn(
47
+ `Reload server disconnected.\nPlease check if the WebSocket server is running properly on ${LOCAL_RELOAD_SOCKET_URL}. This feature detects changes in the code and helps the browser to reload the extension or refresh the current tab.`,
48
+ );
49
+ };
50
+
51
+ return socket;
52
+ }
@@ -0,0 +1,72 @@
1
+ import { WebSocketServer } from 'ws';
2
+ import chokidar from 'chokidar';
3
+ import { clearTimeout } from 'timers';
4
+
5
+ function debounce(callback, delay) {
6
+ let timer;
7
+ return function (...args) {
8
+ clearTimeout(timer);
9
+ timer = setTimeout(() => callback(...args), delay);
10
+ };
11
+ }
12
+
13
+ const LOCAL_RELOAD_SOCKET_PORT = 8081;
14
+ const LOCAL_RELOAD_SOCKET_URL = `ws://localhost:${LOCAL_RELOAD_SOCKET_PORT}`;
15
+ const UPDATE_PENDING_MESSAGE = 'wait_update';
16
+ const UPDATE_REQUEST_MESSAGE = 'do_update';
17
+ const UPDATE_COMPLETE_MESSAGE = 'done_update';
18
+
19
+ class MessageInterpreter {
20
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
21
+ constructor() { }
22
+ static send(message) {
23
+ return JSON.stringify(message);
24
+ }
25
+ static receive(serializedMessage) {
26
+ return JSON.parse(serializedMessage);
27
+ }
28
+ }
29
+
30
+ const clientsThatNeedToUpdate = new Set();
31
+ function initReloadServer() {
32
+ const wss = new WebSocketServer({ port: LOCAL_RELOAD_SOCKET_PORT });
33
+ wss.on('listening', () => console.log(`[HRS] Server listening at ${LOCAL_RELOAD_SOCKET_URL}`));
34
+ wss.on('connection', ws => {
35
+ clientsThatNeedToUpdate.add(ws);
36
+ ws.addEventListener('close', () => clientsThatNeedToUpdate.delete(ws));
37
+ ws.addEventListener('message', event => {
38
+ const message = MessageInterpreter.receive(String(event.data));
39
+ if (message.type === UPDATE_COMPLETE_MESSAGE) {
40
+ ws.close();
41
+ }
42
+ });
43
+ });
44
+ }
45
+ /** CHECK:: src file was updated **/
46
+ const debounceSrc = debounce(function (path) {
47
+ // Normalize path on Windows
48
+ const pathConverted = path.replace(/\\/g, '/');
49
+ clientsThatNeedToUpdate.forEach((ws) => ws.send(MessageInterpreter.send({
50
+ type: UPDATE_PENDING_MESSAGE,
51
+ path: pathConverted,
52
+ })));
53
+ // Delay waiting for public assets to be copied
54
+ }, 400);
55
+ chokidar.watch('src').on('all', (event, path) => debounceSrc(path));
56
+ /** CHECK:: build was completed **/
57
+ const debounceDist = debounce(() => {
58
+ clientsThatNeedToUpdate.forEach((ws) => {
59
+ ws.send(MessageInterpreter.send({ type: UPDATE_REQUEST_MESSAGE }));
60
+ });
61
+ }, 100);
62
+ chokidar.watch('dist').on('all', event => {
63
+ // Ignore unlink, unlinkDir and change events
64
+ // that happen in beginning of build:watch and
65
+ // that will cause ws.send() if it takes more than 400ms
66
+ // to build (which it might). This fixes:
67
+ // https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/100
68
+ if (event !== 'add' && event !== 'addDir')
69
+ return;
70
+ debounceDist();
71
+ });
72
+ initReloadServer();
@@ -0,0 +1,68 @@
1
+ import type { WebSocket } from 'ws';
2
+ import { WebSocketServer } from 'ws';
3
+ import chokidar from 'chokidar';
4
+ import { debounce } from './utils';
5
+ import {
6
+ LOCAL_RELOAD_SOCKET_PORT,
7
+ LOCAL_RELOAD_SOCKET_URL,
8
+ UPDATE_COMPLETE_MESSAGE,
9
+ UPDATE_PENDING_MESSAGE,
10
+ UPDATE_REQUEST_MESSAGE,
11
+ } from './constant';
12
+ import MessageInterpreter from './interpreter';
13
+
14
+ const clientsThatNeedToUpdate: Set<WebSocket> = new Set();
15
+
16
+ function initReloadServer() {
17
+ const wss = new WebSocketServer({ port: LOCAL_RELOAD_SOCKET_PORT });
18
+
19
+ wss.on('listening', () => console.info(`[HRS] Server listening at ${LOCAL_RELOAD_SOCKET_URL}`));
20
+
21
+ wss.on('connection', (ws) => {
22
+ clientsThatNeedToUpdate.add(ws);
23
+
24
+ ws.addEventListener('close', () => clientsThatNeedToUpdate.delete(ws));
25
+ ws.addEventListener('message', (event) => {
26
+ const message = MessageInterpreter.receive(String(event.data));
27
+ if (message.type === UPDATE_COMPLETE_MESSAGE) {
28
+ ws.close();
29
+ }
30
+ });
31
+ });
32
+ }
33
+
34
+ /** CHECK:: src file was updated **/
35
+ const debounceSrc = debounce(function (path: string) {
36
+ // Normalize path on Windows
37
+ const pathConverted = path.replace(/\\/g, '/');
38
+ clientsThatNeedToUpdate.forEach((ws: WebSocket) =>
39
+ ws.send(
40
+ MessageInterpreter.send({
41
+ type: UPDATE_PENDING_MESSAGE,
42
+ path: pathConverted,
43
+ }),
44
+ ),
45
+ );
46
+ // Delay waiting for public assets to be copied
47
+ }, 400);
48
+ chokidar.watch('src').on('all', (event, path) => debounceSrc(path));
49
+
50
+ /** CHECK:: build was completed **/
51
+ const debounceDist = debounce(() => {
52
+ clientsThatNeedToUpdate.forEach((ws: WebSocket) => {
53
+ ws.send(MessageInterpreter.send({ type: UPDATE_REQUEST_MESSAGE }));
54
+ });
55
+ }, 100);
56
+ chokidar.watch('dist').on('all', (event) => {
57
+ // Ignore unlink, unlinkDir and change events
58
+ // that happen in beginning of build:watch and
59
+ // that will cause ws.send() if it takes more than 400ms
60
+ // to build (which it might). This fixes:
61
+ // https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/100
62
+ if (event !== 'add' && event !== 'addDir') {
63
+ return;
64
+ }
65
+ debounceDist();
66
+ });
67
+
68
+ initReloadServer();
@@ -0,0 +1,60 @@
1
+ const LOCAL_RELOAD_SOCKET_PORT = 8081;
2
+ const LOCAL_RELOAD_SOCKET_URL = `ws://localhost:${LOCAL_RELOAD_SOCKET_PORT}`;
3
+ const UPDATE_PENDING_MESSAGE = 'wait_update';
4
+ const UPDATE_REQUEST_MESSAGE = 'do_update';
5
+ const UPDATE_COMPLETE_MESSAGE = 'done_update';
6
+
7
+ class MessageInterpreter {
8
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
9
+ constructor() { }
10
+ static send(message) {
11
+ return JSON.stringify(message);
12
+ }
13
+ static receive(serializedMessage) {
14
+ return JSON.parse(serializedMessage);
15
+ }
16
+ }
17
+
18
+ let needToUpdate = false;
19
+ function initReloadClient({ watchPath, onUpdate, }) {
20
+ const socket = new WebSocket(LOCAL_RELOAD_SOCKET_URL);
21
+ function sendUpdateCompleteMessage() {
22
+ socket.send(MessageInterpreter.send({ type: UPDATE_COMPLETE_MESSAGE }));
23
+ }
24
+ socket.addEventListener('message', event => {
25
+ const message = MessageInterpreter.receive(String(event.data));
26
+ switch (message.type) {
27
+ case UPDATE_REQUEST_MESSAGE: {
28
+ if (needToUpdate) {
29
+ sendUpdateCompleteMessage();
30
+ needToUpdate = false;
31
+ onUpdate();
32
+ }
33
+ return;
34
+ }
35
+ case UPDATE_PENDING_MESSAGE: {
36
+ if (!needToUpdate) {
37
+ needToUpdate = message.path.includes(watchPath);
38
+ }
39
+ return;
40
+ }
41
+ }
42
+ });
43
+ socket.onclose = () => {
44
+ console.warn(`Reload server disconnected.\nPlease check if the WebSocket server is running properly on ${LOCAL_RELOAD_SOCKET_URL}. This feature detects changes in the code and helps the browser to reload the extension or refresh the current tab.`);
45
+ };
46
+ return socket;
47
+ }
48
+
49
+ function addHmrIntoScript(watchPath) {
50
+ initReloadClient({
51
+ watchPath,
52
+ onUpdate: () => {
53
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
54
+ // @ts-ignore
55
+ chrome.runtime.reload();
56
+ },
57
+ });
58
+ }
59
+
60
+ export { addHmrIntoScript as default };
@@ -0,0 +1,12 @@
1
+ import initReloadClient from '../initReloadClient';
2
+
3
+ export default function addHmrIntoScript(watchPath: string) {
4
+ initReloadClient({
5
+ watchPath,
6
+ onUpdate: () => {
7
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
8
+ // @ts-ignore
9
+ chrome.runtime.reload();
10
+ },
11
+ });
12
+ }
@@ -0,0 +1,74 @@
1
+ const LOCAL_RELOAD_SOCKET_PORT = 8081;
2
+ const LOCAL_RELOAD_SOCKET_URL = `ws://localhost:${LOCAL_RELOAD_SOCKET_PORT}`;
3
+ const UPDATE_PENDING_MESSAGE = 'wait_update';
4
+ const UPDATE_REQUEST_MESSAGE = 'do_update';
5
+ const UPDATE_COMPLETE_MESSAGE = 'done_update';
6
+
7
+ class MessageInterpreter {
8
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
9
+ constructor() { }
10
+ static send(message) {
11
+ return JSON.stringify(message);
12
+ }
13
+ static receive(serializedMessage) {
14
+ return JSON.parse(serializedMessage);
15
+ }
16
+ }
17
+
18
+ let needToUpdate = false;
19
+ function initReloadClient({ watchPath, onUpdate, }) {
20
+ const socket = new WebSocket(LOCAL_RELOAD_SOCKET_URL);
21
+ function sendUpdateCompleteMessage() {
22
+ socket.send(MessageInterpreter.send({ type: UPDATE_COMPLETE_MESSAGE }));
23
+ }
24
+ socket.addEventListener('message', event => {
25
+ const message = MessageInterpreter.receive(String(event.data));
26
+ switch (message.type) {
27
+ case UPDATE_REQUEST_MESSAGE: {
28
+ if (needToUpdate) {
29
+ sendUpdateCompleteMessage();
30
+ needToUpdate = false;
31
+ onUpdate();
32
+ }
33
+ return;
34
+ }
35
+ case UPDATE_PENDING_MESSAGE: {
36
+ if (!needToUpdate) {
37
+ needToUpdate = message.path.includes(watchPath);
38
+ }
39
+ return;
40
+ }
41
+ }
42
+ });
43
+ socket.onclose = () => {
44
+ console.warn(`Reload server disconnected.\nPlease check if the WebSocket server is running properly on ${LOCAL_RELOAD_SOCKET_URL}. This feature detects changes in the code and helps the browser to reload the extension or refresh the current tab.`);
45
+ };
46
+ return socket;
47
+ }
48
+
49
+ function addHmrIntoView(watchPath) {
50
+ let pendingReload = false;
51
+ initReloadClient({
52
+ watchPath,
53
+ onUpdate: () => {
54
+ // disable reload when tab is hidden
55
+ if (document.hidden) {
56
+ pendingReload = true;
57
+ return;
58
+ }
59
+ reload();
60
+ },
61
+ });
62
+ // reload
63
+ function reload() {
64
+ pendingReload = false;
65
+ window.location.reload();
66
+ }
67
+ // reload when tab is visible
68
+ function reloadWhenTabIsVisible() {
69
+ !document.hidden && pendingReload && reload();
70
+ }
71
+ document.addEventListener('visibilitychange', reloadWhenTabIsVisible);
72
+ }
73
+
74
+ export { addHmrIntoView as default };
@@ -0,0 +1,29 @@
1
+ import initReloadClient from '../initReloadClient';
2
+
3
+ export default function addHmrIntoView(watchPath: string) {
4
+ let pendingReload = false;
5
+ // reload
6
+ function reload(): void {
7
+ pendingReload = false;
8
+ window.location.reload();
9
+ }
10
+
11
+ // reload when tab is visible
12
+ function reloadWhenTabIsVisible(): void {
13
+ !document.hidden && pendingReload && reload();
14
+ }
15
+
16
+ initReloadClient({
17
+ watchPath,
18
+ onUpdate: () => {
19
+ // disable reload when tab is hidden
20
+ if (document.hidden) {
21
+ pendingReload = true;
22
+ return;
23
+ }
24
+ reload();
25
+ },
26
+ });
27
+
28
+ document.addEventListener('visibilitychange', reloadWhenTabIsVisible);
29
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReloadMessage, SerializedMessage } from './types';
2
+
3
+ export default class MessageInterpreter {
4
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
5
+ private constructor() {}
6
+
7
+ static send(message: ReloadMessage): SerializedMessage {
8
+ return JSON.stringify(message);
9
+ }
10
+ static receive(serializedMessage: SerializedMessage): ReloadMessage {
11
+ return JSON.parse(serializedMessage) as ReloadMessage;
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ import { UPDATE_COMPLETE_MESSAGE, UPDATE_PENDING_MESSAGE, UPDATE_REQUEST_MESSAGE } from '../constant';
2
+
3
+ type UpdatePendingMessage = {
4
+ type: typeof UPDATE_PENDING_MESSAGE;
5
+ path: string;
6
+ };
7
+
8
+ type UpdateRequestMessage = {
9
+ type: typeof UPDATE_REQUEST_MESSAGE;
10
+ };
11
+
12
+ type UpdateCompleteMessage = { type: typeof UPDATE_COMPLETE_MESSAGE };
13
+
14
+ export type SerializedMessage = string;
15
+ export type ReloadMessage = UpdateCompleteMessage | UpdateRequestMessage | UpdatePendingMessage;
@@ -0,0 +1,28 @@
1
+ import typescript from '@rollup/plugin-typescript';
2
+
3
+ const plugins = [typescript()];
4
+
5
+ export default [
6
+ {
7
+ plugins,
8
+ input: 'utils/reload/initReloadServer.ts',
9
+ output: {
10
+ file: 'utils/reload/initReloadServer.js',
11
+ },
12
+ external: ['ws', 'chokidar', 'timers'],
13
+ },
14
+ {
15
+ plugins,
16
+ input: 'utils/reload/injections/script.ts',
17
+ output: {
18
+ file: 'utils/reload/injections/script.js',
19
+ },
20
+ },
21
+ {
22
+ plugins,
23
+ input: 'utils/reload/injections/view.ts',
24
+ output: {
25
+ file: 'utils/reload/injections/view.js',
26
+ },
27
+ },
28
+ ];
@@ -0,0 +1,9 @@
1
+ import { clearTimeout } from 'timers';
2
+
3
+ export function debounce<A extends unknown[]>(callback: (...args: A) => void, delay: number) {
4
+ let timer: NodeJS.Timeout;
5
+ return function (...args: A) {
6
+ clearTimeout(timer);
7
+ timer = setTimeout(() => callback(...args), delay);
8
+ };
9
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,89 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import path, { resolve } from 'path';
4
+ import makeManifest from './utils/plugins/make-manifest';
5
+ import customDynamicImport from './utils/plugins/custom-dynamic-import';
6
+ import addHmr from './utils/plugins/add-hmr';
7
+ import watchRebuild from './utils/plugins/watch-rebuild';
8
+ import manifest from './manifest';
9
+
10
+ const rootDir = resolve(__dirname);
11
+ const srcDir = resolve(rootDir, 'src');
12
+ const pagesDir = resolve(srcDir, 'pages');
13
+ const assetsDir = resolve(srcDir, 'assets');
14
+ const outDir = resolve(rootDir, 'dist');
15
+ const publicDir = resolve(rootDir, 'public');
16
+
17
+ const isDev = process.env.__DEV__ === 'true';
18
+ const isProduction = !isDev;
19
+
20
+ function generateKey(): string {
21
+ return `${(Date.now() / 100).toFixed()}`;
22
+ }
23
+
24
+ function firstUpperCase(str: string) {
25
+ const firstAlphabet = new RegExp(/( |^)[a-z]/, 'g');
26
+ return str.toLowerCase().replace(firstAlphabet, (L) => L.toUpperCase());
27
+ }
28
+
29
+ let cacheInvalidationKey: string = generateKey();
30
+ function regenerateCacheInvalidationKey() {
31
+ cacheInvalidationKey = generateKey();
32
+ return cacheInvalidationKey;
33
+ }
34
+
35
+ // ENABLE HMR IN BACKGROUND SCRIPT
36
+ const enableHmrInBackgroundScript = true;
37
+
38
+ export default defineConfig({
39
+ resolve: {
40
+ alias: {
41
+ '@root': rootDir,
42
+ '@src': srcDir,
43
+ '@assets': assetsDir,
44
+ '@pages': pagesDir,
45
+ },
46
+ },
47
+ plugins: [
48
+ react(),
49
+ makeManifest(manifest, {
50
+ isDev,
51
+ contentScriptCssKey: regenerateCacheInvalidationKey(),
52
+ }),
53
+ customDynamicImport(),
54
+ addHmr({ background: enableHmrInBackgroundScript, view: true }),
55
+ watchRebuild(),
56
+ ],
57
+ publicDir,
58
+ build: {
59
+ outDir,
60
+ /** Can slowDown build speed. */
61
+ // sourcemap: isDev,
62
+ minify: isProduction,
63
+ modulePreload: false,
64
+ reportCompressedSize: isProduction,
65
+ rollupOptions: {
66
+ input: {
67
+ // devtools: resolve(pagesDir, 'devtools', 'index.html'),
68
+ content: resolve(pagesDir, 'content', 'index.ts'),
69
+ background: resolve(pagesDir, 'background', 'index.ts'),
70
+ contentStyle: resolve(pagesDir, 'content', 'style.scss'),
71
+ popup: resolve(pagesDir, 'popup', 'index.html'),
72
+ options: resolve(pagesDir, 'options', 'index.html'),
73
+ },
74
+ output: {
75
+ entryFileNames: 'src/pages/[name]/index.js',
76
+ chunkFileNames: isDev ? 'assets/js/[name].js' : 'assets/js/[name].[hash].js',
77
+ assetFileNames: (assetInfo) => {
78
+ const { dir, name: _name } = path.parse(assetInfo.name);
79
+ const assetFolder = dir.split('/').at(-1);
80
+ const name = assetFolder + firstUpperCase(_name);
81
+ if (name === 'contentStyle') {
82
+ return `assets/css/contentStyle${cacheInvalidationKey}.chunk.css`;
83
+ }
84
+ return `assets/[ext]/${name}.chunk.[ext]`;
85
+ },
86
+ },
87
+ },
88
+ },
89
+ });