diff --git a/chrome-extension/manifest.js b/chrome-extension/manifest.js index 7d43a33fa..bf65476d4 100755 --- a/chrome-extension/manifest.js +++ b/chrome-extension/manifest.js @@ -27,7 +27,8 @@ const manifest = deepmerge( name: '__MSG_extensionName__', version: packageJson.version, description: '__MSG_extensionDescription__', - permissions: ['storage'], + host_permissions: [''], + permissions: ['storage', 'scripting'], options_page: 'options/index.html', background: { service_worker: 'background.iife.js', diff --git a/packages/shared/build.mjs b/packages/shared/build.mjs index 5981ff505..0e96d84f2 100644 --- a/packages/shared/build.mjs +++ b/packages/shared/build.mjs @@ -1,15 +1,15 @@ -import * as esbuild from "esbuild" +import * as esbuild from 'esbuild'; /** * @type { import("esbuild").BuildOptions } */ const buildOptions = { - entryPoints: ["./index.ts", "./lib/**/*.ts", "./lib/**/*.tsx"], - tsconfig: "./tsconfig.json", + entryPoints: ['./index.ts', './lib/**/*.ts', './lib/**/*.tsx'], + tsconfig: './tsconfig.json', bundle: false, target: 'es6', - outdir: "./dist", + outdir: './dist', sourcemap: true, -} +}; await esbuild.build(buildOptions); diff --git a/packages/ui/build.mjs b/packages/ui/build.mjs index b9b9f4774..be04d2979 100644 --- a/packages/ui/build.mjs +++ b/packages/ui/build.mjs @@ -1,18 +1,18 @@ -import * as esbuild from "esbuild" -import * as fs from "fs"; -import { resolve } from "node:path"; +import * as esbuild from 'esbuild'; +import * as fs from 'fs'; +import { resolve } from 'node:path'; /** * @type { import("esbuild").BuildOptions } */ const buildOptions = { - entryPoints: ["./index.ts","./tailwind.config.ts", "./lib/**/*.ts", "./lib/**/*.tsx"], - tsconfig: "./tsconfig.json", + entryPoints: ['./index.ts', './tailwind.config.ts', './lib/**/*.ts', './lib/**/*.tsx'], + tsconfig: './tsconfig.json', bundle: false, target: 'es6', - outdir: "./dist", + outdir: './dist', sourcemap: true, -} +}; await esbuild.build(buildOptions); -fs.copyFileSync(resolve("lib", "global.css"),resolve("dist", "global.css")) +fs.copyFileSync(resolve('lib', 'global.css'), resolve('dist', 'global.css')); diff --git a/pages/content-runtime/lib/app.tsx b/pages/content-runtime/lib/app.tsx new file mode 100644 index 000000000..8cbbd3777 --- /dev/null +++ b/pages/content-runtime/lib/app.tsx @@ -0,0 +1,9 @@ +import { useEffect } from 'react'; + +export default function App() { + useEffect(() => { + console.log('runtime content view loaded'); + }, []); + + return
runtime content view
; +} diff --git a/pages/content-runtime/lib/index.css b/pages/content-runtime/lib/index.css new file mode 100644 index 000000000..151be5aab --- /dev/null +++ b/pages/content-runtime/lib/index.css @@ -0,0 +1,3 @@ +.runtime-content-view-text { + font-size: 20px; +} diff --git a/pages/content-runtime/lib/index.ts b/pages/content-runtime/lib/index.ts new file mode 100644 index 000000000..bea5c4046 --- /dev/null +++ b/pages/content-runtime/lib/index.ts @@ -0,0 +1,11 @@ +/** + * DO NOT USE import someModule from '...'; + * + * @issue-url https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/issues/160 + * + * Chrome extensions don't support modules in content scripts. + * If you want to use other modules in content scripts, you need to import them via these files. + * + */ +import('@lib/root'); +console.log('runtime script loaded'); diff --git a/pages/content-runtime/lib/root.tsx b/pages/content-runtime/lib/root.tsx new file mode 100644 index 000000000..956699d2c --- /dev/null +++ b/pages/content-runtime/lib/root.tsx @@ -0,0 +1,38 @@ +import { createRoot } from 'react-dom/client'; +import App from '@lib/app'; +// eslint-disable-next-line +// @ts-ignore +import injectedStyle from '@lib/index.css?inline'; + +const root = document.createElement('div'); +root.id = 'chrome-extension-boilerplate-react-vite-runtime-content-view-root'; + +document.body.append(root); + +const rootIntoShadow = document.createElement('div'); +rootIntoShadow.id = 'shadow-root'; + +const shadowRoot = root.attachShadow({ mode: 'open' }); +shadowRoot.appendChild(rootIntoShadow); + +/** Inject styles into shadow dom */ +const globalStyleSheet = new CSSStyleSheet(); +globalStyleSheet.replaceSync(injectedStyle); +shadowRoot.adoptedStyleSheets = [globalStyleSheet]; +shadowRoot.appendChild(rootIntoShadow); +/** + * In the firefox environment, the adoptedStyleSheets bug may prevent style from being applied properly. + * + * @url https://bugzilla.mozilla.org/show_bug.cgi?id=1770592 + * @url https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/pull/174 + * + * Please refer to the links above and try the following code if you encounter the issue. + * + * ```ts + * const styleElement = document.createElement('style'); + * styleElement.innerHTML = injectedStyle; + * shadowRoot.appendChild(styleElement); + * ``` + */ + +createRoot(rootIntoShadow).render(); diff --git a/pages/content-runtime/package.json b/pages/content-runtime/package.json new file mode 100644 index 000000000..6f4c0a540 --- /dev/null +++ b/pages/content-runtime/package.json @@ -0,0 +1,26 @@ +{ + "name": "@chrome-extension-boilerplate/content-runtime-script", + "version": "0.0.1", + "description": "chrome extension content runtime script", + "private": true, + "sideEffects": true, + "files": [ + "dist/**" + ], + "scripts": { + "clean": "rimraf ./dist", + "build": "pnpm run clean && pnpm type-check && vite build", + "build:watch": "cross-env __DEV__=true vite build -w --mode development", + "dev": "pnpm build:watch", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "pnpm lint --fix", + "prettier": "prettier . --write --ignore-path ../../.prettierignore", + "type-check": "tsc --noEmit" + }, + "dependencies": {}, + "devDependencies": { + "@chrome-extension-boilerplate/tsconfig": "workspace:*", + "@chrome-extension-boilerplate/hmr": "workspace:*", + "@chrome-extension-boilerplate/vite-config": "workspace:*" + } +} diff --git a/pages/content-runtime/tsconfig.json b/pages/content-runtime/tsconfig.json new file mode 100644 index 000000000..ccbab7821 --- /dev/null +++ b/pages/content-runtime/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@chrome-extension-boilerplate/tsconfig/base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@lib/*": ["lib/*"] + }, + "types": ["chrome"] + }, + "include": ["lib"] +} diff --git a/pages/content-runtime/vite.config.mts b/pages/content-runtime/vite.config.mts new file mode 100644 index 000000000..fe1a06ad4 --- /dev/null +++ b/pages/content-runtime/vite.config.mts @@ -0,0 +1,23 @@ +import { resolve } from 'path'; +import { withPageConfig } from '@chrome-extension-boilerplate/vite-config'; + +const rootDir = resolve(__dirname); +const libDir = resolve(rootDir, 'lib'); + +export default withPageConfig({ + resolve: { + alias: { + '@lib': libDir, + }, + }, + publicDir: resolve(rootDir, 'public'), + build: { + lib: { + formats: ['iife'], + entry: resolve(__dirname, 'lib/index.ts'), + name: 'ContentRuntimeScript', + fileName: 'index', + }, + outDir: resolve(rootDir, '..', '..', 'dist', 'content-runtime'), + }, +}); diff --git a/pages/content-ui/src/index.tsx b/pages/content-ui/src/index.tsx index 6344a1151..e5a02719a 100644 --- a/pages/content-ui/src/index.tsx +++ b/pages/content-ui/src/index.tsx @@ -18,8 +18,21 @@ shadowRoot.appendChild(rootIntoShadow); /** Inject styles into shadow dom */ const globalStyleSheet = new CSSStyleSheet(); globalStyleSheet.replaceSync(tailwindcssOutput); - shadowRoot.adoptedStyleSheets = [globalStyleSheet]; shadowRoot.appendChild(rootIntoShadow); +/** + * In the firefox environment, the adoptedStyleSheets bug may prevent style from being applied properly. + * + * @url https://bugzilla.mozilla.org/show_bug.cgi?id=1770592 + * @url https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/pull/174 + * + * Please refer to the links above and try the following code if you encounter the issue. + * + + * const styleElement = document.createElement('style'); + * styleElement.innerHTML = tailwindcssOutput; + * shadowRoot.appendChild(styleElement); + * ``` + */ createRoot(rootIntoShadow).render(); diff --git a/pages/content-ui/src/tailwind-output.css b/pages/content-ui/src/tailwind-output.css index ea0c743a1..c61733b6a 100644 --- a/pages/content-ui/src/tailwind-output.css +++ b/pages/content-ui/src/tailwind-output.css @@ -44,10 +44,9 @@ html, -moz-tab-size: 4; /* 3 */ -o-tab-size: 4; - tab-size: 4; + tab-size: 4; /* 3 */ - font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', - 'Noto Color Emoji'; + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ font-feature-settings: normal; /* 5 */ @@ -90,7 +89,7 @@ Add the correct text decoration in Chrome, Edge, and Safari. abbr:where([title]) { -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; + text-decoration: underline dotted; } /* @@ -136,7 +135,7 @@ code, kbd, samp, pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ font-feature-settings: normal; /* 2 */ @@ -379,8 +378,7 @@ textarea { 2. Set the default placeholder color to the user's configured gray 400 color. */ -input::-moz-placeholder, -textarea::-moz-placeholder { +input::-moz-placeholder, textarea::-moz-placeholder { opacity: 1; /* 1 */ color: #9ca3af; @@ -400,7 +398,7 @@ Set the default cursor for buttons. */ button, -[role='button'] { +[role="button"] { cursor: pointer; } @@ -448,9 +446,7 @@ video { display: none; } -*, -::before, -::after { +*, ::before, ::after { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; diff --git a/pages/popup/package.json b/pages/popup/package.json index ad779d91a..3c1e66cbf 100644 --- a/pages/popup/package.json +++ b/pages/popup/package.json @@ -19,7 +19,9 @@ }, "dependencies": { "@chrome-extension-boilerplate/shared": "workspace:*", - "@chrome-extension-boilerplate/storage": "workspace:*" + "@chrome-extension-boilerplate/storage": "workspace:*", + "@chrome-extension-boilerplate/content-runtime-script": "workspace:*", + "@types/node": "^20.14.10" }, "devDependencies": { "@chrome-extension-boilerplate/tailwindcss-config": "workspace:*", diff --git a/pages/popup/src/Popup.tsx b/pages/popup/src/Popup.tsx index 40f3d1f00..344fb1956 100644 --- a/pages/popup/src/Popup.tsx +++ b/pages/popup/src/Popup.tsx @@ -8,6 +8,15 @@ const Popup = () => { const isLight = theme === 'light'; const logo = isLight ? 'popup/logo_vertical.svg' : 'popup/logo_vertical_dark.svg'; + const injectContentScript = async () => { + const [tab] = await chrome.tabs.query({ currentWindow: true, active: true }); + + await chrome.scripting.executeScript({ + target: { tabId: tab.id! }, + files: ['content-runtime/index.iife.js'], + }); + }; + return (
@@ -15,6 +24,14 @@ const Popup = () => {

Edit pages/popup/src/Popup.tsx

+ Toggle theme
@@ -29,7 +46,7 @@ const ToggleButton = (props: ComponentPropsWithoutRef<'button'>) => { props.className + ' ' + 'font-bold mt-4 py-1 px-4 rounded shadow hover:scale-105 ' + - (theme === 'light' ? 'bg-white text-black' : 'bg-black text-white') + (theme === 'light' ? 'bg-white text-black shadow-black' : 'bg-black text-white') } onClick={exampleThemeStorage.toggle}> {props.children} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba5d6beee..5e1fa99bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -255,6 +255,18 @@ importers: specifier: workspace:* version: link:../../packages/vite-config + pages/content-runtime: + devDependencies: + '@chrome-extension-boilerplate/hmr': + specifier: workspace:* + version: link:../../packages/hmr + '@chrome-extension-boilerplate/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@chrome-extension-boilerplate/vite-config': + specifier: workspace:* + version: link:../../packages/vite-config + pages/content-ui: dependencies: '@chrome-extension-boilerplate/shared': @@ -355,12 +367,18 @@ importers: pages/popup: dependencies: + '@chrome-extension-boilerplate/content-runtime-script': + specifier: workspace:* + version: link:../content-runtime '@chrome-extension-boilerplate/shared': specifier: workspace:* version: link:../../packages/shared '@chrome-extension-boilerplate/storage': specifier: workspace:* version: link:../../packages/storage + '@types/node': + specifier: ^20.14.10 + version: 20.14.10 devDependencies: '@chrome-extension-boilerplate/tailwindcss-config': specifier: workspace:*