From a994a9ee3a757855edf35ea7055eec5aee3bd78f Mon Sep 17 00:00:00 2001 From: linka Date: Tue, 19 Apr 2022 10:26:08 +0800 Subject: [PATCH] feat: support through button and shortcut to copy github path --- .eslintignore | 4 + .eslintrc | 3 + .github/FUNDING.yml | 1 + .gitignore | 18 + .npmrc | 1 + .vscode/extensions.json | 9 + .vscode/settings.json | 13 + LICENSE | 21 + README.md | 132 + build.ts | 115 + package.json | 73 + pnpm-lock.yaml | 6188 +++++++++++++++++++++++++++ scripts/manifest.ts | 11 + scripts/prepare.ts | 66 + scripts/utils.ts | 11 + shim.d.ts | 13 + src/assets/icon-128.png | Bin 0 -> 5497 bytes src/assets/icon-blue-128.png | Bin 0 -> 12005 bytes src/assets/icon-blue-512.png | Bin 0 -> 63182 bytes src/assets/icon-blue-96.png | Bin 0 -> 9105 bytes src/assets/icon-blue.svg | 9 + src/assets/icon.svg | 9 + src/background/contentScriptHMR.ts | 28 + src/background/main.ts | 105 + src/components/Logo.vue | 9 + src/components/README.md | 11 + src/components/Switch.vue | 115 + src/composables/useStorageLocal.ts | 30 + src/contentScripts/index.ts | 60 + src/contentScripts/views/App.vue | 28 + src/contentScripts/views/Github.vue | 19 + src/env.ts | 14 + src/global.d.ts | 6 + src/logic/index.ts | 10 + src/logic/storage.ts | 12 + src/manifest.ts | 157 + src/options/Options.vue | 19 + src/options/index.html | 12 + src/options/main.ts | 6 + src/popup/Popup.vue | 37 + src/popup/index.html | 12 + src/popup/main.ts | 6 + src/styles/index.ts | 2 + src/styles/main.css | 24 + tsconfig.json | 23 + vite.config.background.ts | 51 + vite.config.content.ts | 44 + vite.config.ts | 112 + windi.config.ts | 13 + 49 files changed, 7662 insertions(+) create mode 100644 .eslintignore create mode 100644 .eslintrc create mode 100644 .github/FUNDING.yml create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.ts create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 scripts/manifest.ts create mode 100644 scripts/prepare.ts create mode 100644 scripts/utils.ts create mode 100644 shim.d.ts create mode 100644 src/assets/icon-128.png create mode 100644 src/assets/icon-blue-128.png create mode 100644 src/assets/icon-blue-512.png create mode 100644 src/assets/icon-blue-96.png create mode 100644 src/assets/icon-blue.svg create mode 100644 src/assets/icon.svg create mode 100644 src/background/contentScriptHMR.ts create mode 100644 src/background/main.ts create mode 100644 src/components/Logo.vue create mode 100644 src/components/README.md create mode 100644 src/components/Switch.vue create mode 100644 src/composables/useStorageLocal.ts create mode 100644 src/contentScripts/index.ts create mode 100644 src/contentScripts/views/App.vue create mode 100644 src/contentScripts/views/Github.vue create mode 100644 src/env.ts create mode 100644 src/global.d.ts create mode 100644 src/logic/index.ts create mode 100644 src/logic/storage.ts create mode 100644 src/manifest.ts create mode 100644 src/options/Options.vue create mode 100644 src/options/index.html create mode 100644 src/options/main.ts create mode 100644 src/popup/Popup.vue create mode 100644 src/popup/index.html create mode 100644 src/popup/main.ts create mode 100644 src/styles/index.ts create mode 100644 src/styles/main.css create mode 100644 tsconfig.json create mode 100644 vite.config.background.ts create mode 100644 vite.config.content.ts create mode 100644 vite.config.ts create mode 100644 windi.config.ts diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a8db16f --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +dist +node_modules +public +extension diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..406dd40 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "@aliuq" +} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7246382 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: antfu diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..673a337 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.DS_Store +.idea/ +.vite-ssg-dist +.vite-ssg-temp +*.crx +*.local +*.log +*.pem +*.xpi +*.zip +dist +dist-ssr +extension/ +node_modules +src/auto-imports.d.ts +src/components.d.ts +Photos/ +.output/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..bf2e764 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..320368c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "johnsoncodehk.volar", + "antfu.iconify", + "dbaeumer.vscode-eslint", + "voorjaar.windicss-intellisense", + "csstools.postcss" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..dac0530 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "cSpell.words": ["Vitesse"], + "typescript.tsdk": "node_modules/typescript/lib", + "volar.tsPlugin": true, + "volar.tsPluginStatus": false, + "vite.autoStart": false, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "files.associations": { + "*.css": "postcss" + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9b031a2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Anthony Fu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f66c728 --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# WebExtension Vite Starter + +A [Vite](https://vitejs.dev/) powered WebExtension ([Chrome](https://developer.chrome.com/docs/extensions/reference/), [FireFox](https://addons.mozilla.org/en-US/developers/), etc.) starter template. + +

+Popup
+
+Options Page
+
+Inject Vue App into the Content Script
+ +

+ +## Features + +- ⚡️ **Instant HMR** - use **Vite** on dev (no more refresh!) +- 🥝 Vue 3 - Composition API, [` + + diff --git a/src/components/README.md b/src/components/README.md new file mode 100644 index 0000000..f9ed8ea --- /dev/null +++ b/src/components/README.md @@ -0,0 +1,11 @@ +## Components + +Components in this dir will be auto-registered and on-demand, powered by [`vite-plugin-components`](https://github.com/antfu/vite-plugin-components). + +Components can be shared in all views. + +### Icons + +You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/). + +It will only bundle the icons you use. Check out [vite-plugin-icons](https://github.com/antfu/vite-plugin-icons) for more details. diff --git a/src/components/Switch.vue b/src/components/Switch.vue new file mode 100644 index 0000000..1472f3e --- /dev/null +++ b/src/components/Switch.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/src/composables/useStorageLocal.ts b/src/composables/useStorageLocal.ts new file mode 100644 index 0000000..b170893 --- /dev/null +++ b/src/composables/useStorageLocal.ts @@ -0,0 +1,30 @@ +import { storage } from 'webextension-polyfill' +import type { + MaybeRef, + RemovableRef, + StorageAsyncOptions, + StorageLikeAsync, +} from '@vueuse/core' +import { + useStorageAsync, +} from '@vueuse/core' + +const storageLocal: StorageLikeAsync = { + removeItem(key: string) { + return storage.local.remove(key) + }, + + setItem(key: string, value: string) { + return storage.local.set({ [key]: value }) + }, + + async getItem(key: string) { + return (await storage.local.get(key))[key] + }, +} + +export const useStorageLocal = ( + key: string, + initialValue: MaybeRef, + options?: StorageAsyncOptions, +): RemovableRef => useStorageAsync(key, initialValue, storageLocal, options) diff --git a/src/contentScripts/index.ts b/src/contentScripts/index.ts new file mode 100644 index 0000000..7047fbc --- /dev/null +++ b/src/contentScripts/index.ts @@ -0,0 +1,60 @@ +/* eslint-disable no-console */ +import { onMessage } from 'webext-bridge' +import { createApp } from 'vue' +import { useClipboard } from '@vueuse/core' +import Github from './views/Github.vue' +import { log } from '~/logic' + +// Firefox `browser.tabs.executeScript()` requires scripts return a primitive value +(() => { + log('Setup from content script') + + onMessage('modify-pages-changed', ({ data }) => { + log(`Modify pages changed: [${data.source}]`) + renderCopyEl(data.source) + }) + + onMessage('update-element', ({ data }) => { + log('Update element') + log(data) + if (data.status) + renderCopyEl(data.source as string) + else + removeCopyEl() + }) + + onMessage('copy-source', ({ data }) => { + if (!data.source) + return + const { copy } = useClipboard({ source: data.source }) + copy() + }) +})() + +function renderCopyEl(source: string) { + try { + // Github: Find last element by class name `d-none` + const container = Array.prototype.slice.call( + document.querySelectorAll('.file-navigation .d-none'), + -1, + )[0] + if (!container) + return + const parent = container.parentNode + const el = parent?.querySelector('.webext-degit') + el && el.remove() + const root = document.createElement('div') + root.classList.add('webext-degit') + root.classList.add(container.classList.contains('btn') ? 'mr-2' : 'ml-2') + parent?.insertBefore(root, container) + createApp(Github, { source }).mount(root) + } + catch (err) { + console.error(err) + } +} + +function removeCopyEl(container = document) { + const el = container.querySelector('.webext-degit') + el && el.remove() +} diff --git a/src/contentScripts/views/App.vue b/src/contentScripts/views/App.vue new file mode 100644 index 0000000..c2d1d79 --- /dev/null +++ b/src/contentScripts/views/App.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/contentScripts/views/Github.vue b/src/contentScripts/views/Github.vue new file mode 100644 index 0000000..3bd1b37 --- /dev/null +++ b/src/contentScripts/views/Github.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 0000000..34f43c4 --- /dev/null +++ b/src/env.ts @@ -0,0 +1,14 @@ +const forbiddenProtocols = [ + 'chrome-extension://', + 'chrome-search://', + 'chrome://', + 'devtools://', + 'edge://', + 'https://chrome.google.com/webstore', +] + +export function isForbiddenUrl(url: string): boolean { + return forbiddenProtocols.some(protocol => url.startsWith(protocol)) +} + +export const isFirefox = navigator.userAgent.includes('Firefox') diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..fbf42df --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,6 @@ +declare const __DEV__: boolean + +declare module '*.vue' { + const component: any + export default component +} diff --git a/src/logic/index.ts b/src/logic/index.ts new file mode 100644 index 0000000..40920d5 --- /dev/null +++ b/src/logic/index.ts @@ -0,0 +1,10 @@ +export * from './storage' + +export function log(msg: string | object) { + if (typeof msg === 'object') + // eslint-disable-next-line no-console + console.log(JSON.stringify(msg, null, 2)) + else + // eslint-disable-next-line no-console + console.log(`[degit-webext] ${msg}`) +} diff --git a/src/logic/storage.ts b/src/logic/storage.ts new file mode 100644 index 0000000..abfc883 --- /dev/null +++ b/src/logic/storage.ts @@ -0,0 +1,12 @@ +import { useStorageLocal } from '~/composables/useStorageLocal' + +const serializer = { + read: (raw: any) => raw, + write: (raw: any) => raw, +} + +export const storageDemo = useStorageLocal('webext-demo', 'Storage Demo') + +export const showElement = useStorageLocal('show-element', true, { serializer }) +export const enableShortcut = useStorageLocal('enable-shortcut', false, { serializer }) +export const shortcut = useStorageLocal('shortcut', 'Alt+Shift+C') diff --git a/src/manifest.ts b/src/manifest.ts new file mode 100644 index 0000000..2f696be --- /dev/null +++ b/src/manifest.ts @@ -0,0 +1,157 @@ +import fs from 'fs-extra' +import type { Manifest } from 'webextension-polyfill' +import type PkgType from '../package.json' +import { isDev, port, r } from '../scripts/utils' + +const isFirefox = process.env.TARGET === 'firefox' + +export async function getManifest() { + const pkg = await fs.readJSON(r('package.json')) as typeof PkgType + + // update this file to update this manifest.json + // can also be conditional based on your need + const manifest: Manifest.WebExtensionManifest = { + manifest_version: isFirefox ? 2 : 3, + name: pkg.displayName || pkg.name, + version: pkg.version, + description: pkg.description, + ...(isFirefox + ? { + browser_action: { + default_icon: './assets/icon-512.png', + default_popup: './dist/popup/index.html', + }, + } + : { + action: { + default_icon: './assets/icon-512.png', + default_popup: './dist/popup/index.html', + }, + }), + // options_ui: { + // page: './dist/options/index.html', + // open_in_tab: true, + // }, + background: isFirefox + ? { + scripts: ['./dist/background/background.js'], + } + : { + service_worker: './dist/background/background.js', + }, + icons: { + 16: './assets/icon-512.png', + 48: './assets/icon-512.png', + 128: './assets/icon-512.png', + }, + permissions: [ + 'tabs', + 'storage', + 'activeTab', + ], + host_permissions: [ + 'http://github.com/*', + 'https://github.com/*', + ], + content_scripts: [{ + matches: ['http://github.com/*', 'https://github.com/*'], + js: ['./dist/contentScripts/index.global.js'], + }], + web_accessible_resources: isFirefox + ? ['dist/contentScripts/style.css'] + : [{ + resources: ['dist/contentScripts/style.css'], + matches: [''], + }], + commands: { + 'copy-path': { + description: 'Copy the current page degit path', + suggested_key: { + default: 'Alt+Shift+C', + mac: 'Alt+Shift+C', + }, + }, + }, + content_security_policy: { + extension_pages: 'script-src \'self\'; object-src \'self\'', + }, + } + + if (isDev) { + // for content script, as browsers will cache them for each reload, + // we use a background script to always inject the latest version + // see src/background/contentScriptHMR.ts + delete manifest.content_scripts + manifest.permissions?.push('webNavigation') + + // this is required on dev for Vite script to load + manifest.content_security_policy = { + extension_pages: `script-src 'self' http://localhost:${port}; object-src \'self\' http://localhost:${port}`, + } + } + + return manifest +} + +// import fs from 'fs-extra' +// import type { Manifest } from 'webextension-polyfill' +// import type PkgType from '../package.json' +// import { isDev, port, r } from '../scripts/utils' + +// export async function getManifest() { +// const pkg = await fs.readJSON(r('package.json')) as typeof PkgType + +// // update this file to update this manifest.json +// // can also be conditional based on your need +// const manifest: Manifest.WebExtensionManifest = { +// manifest_version: 2, +// name: pkg.displayName || pkg.name, +// version: pkg.version, +// description: pkg.description, +// browser_action: { +// default_icon: './assets/icon-512.png', +// default_popup: './dist/popup/index.html', +// }, +// options_ui: { +// page: './dist/options/index.html', +// open_in_tab: true, +// chrome_style: true, +// }, +// background: { +// page: './dist/background/index.html', +// persistent: false, +// }, +// icons: { +// 16: './assets/icon-512.png', +// 48: './assets/icon-512.png', +// 128: './assets/icon-512.png', +// }, +// permissions: [ +// 'tabs', +// 'storage', +// 'activeTab', +// 'http://*/', +// 'https://*/', +// ], +// content_scripts: [{ +// matches: ['http://*/*', 'https://*/*'], +// js: ['./dist/contentScripts/index.global.js'], +// }], +// web_accessible_resources: [ +// 'dist/contentScripts/style.css', +// ], +// } + +// if (isDev) { +// // for content script, as browsers will cache them for each reload, +// // we use a background script to always inject the latest version +// // see src/background/contentScriptHMR.ts +// delete manifest.content_scripts +// manifest.permissions?.push('webNavigation') + +// // this is required on dev for Vite script to load +// manifest.content_security_policy = `script-src \'self\' http://localhost:${port}; object-src \'self\'` +// } + +// return manifest +// } diff --git a/src/options/Options.vue b/src/options/Options.vue new file mode 100644 index 0000000..79803cb --- /dev/null +++ b/src/options/Options.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/options/index.html b/src/options/index.html new file mode 100644 index 0000000..dbd67cb --- /dev/null +++ b/src/options/index.html @@ -0,0 +1,12 @@ + + + + + + Options + + +
+ + + diff --git a/src/options/main.ts b/src/options/main.ts new file mode 100644 index 0000000..1a911d5 --- /dev/null +++ b/src/options/main.ts @@ -0,0 +1,6 @@ +import { createApp } from 'vue' +import App from './Options.vue' +import '../styles' + +const app = createApp(App) +app.mount('#app') diff --git a/src/popup/Popup.vue b/src/popup/Popup.vue new file mode 100644 index 0000000..c7c3479 --- /dev/null +++ b/src/popup/Popup.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/popup/index.html b/src/popup/index.html new file mode 100644 index 0000000..032a15d --- /dev/null +++ b/src/popup/index.html @@ -0,0 +1,12 @@ + + + + + + Popup + + +
+ + + diff --git a/src/popup/main.ts b/src/popup/main.ts new file mode 100644 index 0000000..f7901f4 --- /dev/null +++ b/src/popup/main.ts @@ -0,0 +1,6 @@ +import { createApp } from 'vue' +import App from './Popup.vue' +import '../styles' + +const app = createApp(App) +app.mount('#app') diff --git a/src/styles/index.ts b/src/styles/index.ts new file mode 100644 index 0000000..8200a64 --- /dev/null +++ b/src/styles/index.ts @@ -0,0 +1,2 @@ +import './main.css' +import 'virtual:windi.css' diff --git a/src/styles/main.css b/src/styles/main.css new file mode 100644 index 0000000..4cc076b --- /dev/null +++ b/src/styles/main.css @@ -0,0 +1,24 @@ +html, +body, +#app { + margin: 0; + padding: 0; +} + +a, a:active, a:visited { + color: inherit; +} + +.btn { + @apply px-4 py-1 rounded inline-block + bg-teal-600 text-white cursor-pointer + hover:bg-teal-700 + disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50; +} + +.icon-btn { + @apply inline-block cursor-pointer select-none + opacity-75 transition duration-200 ease-in-out + hover:opacity-100 hover:text-teal-600; + font-size: 0.9em; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5e0e298 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "module": "ESNext", + "target": "es2016", + "lib": ["DOM", "ESNext"], + "strict": true, + "esModuleInterop": true, + "incremental": false, + "skipLibCheck": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "noUnusedLocals": true, + "forceConsistentCasingInFileNames": true, + "types": [ + "vite/client" + ], + "paths": { + "~/*": ["src/*"] + } + }, + "exclude": ["dist", "node_modules"] +} diff --git a/vite.config.background.ts b/vite.config.background.ts new file mode 100644 index 0000000..8d7bfbf --- /dev/null +++ b/vite.config.background.ts @@ -0,0 +1,51 @@ +import { defineConfig } from 'vite' +import WindiCSS from 'vite-plugin-windicss' +import { sharedConfig } from './vite.config' +import { isDev, r } from './scripts/utils' +import windiConfig from './windi.config' + +// bundling the content script using Vite +export default defineConfig({ + ...sharedConfig, + base: 'http://localhost:3304/', + server: { + port: 3304, + hmr: { + host: 'localhost', + }, + }, + build: { + watch: isDev + ? {} + : undefined, + outDir: r('extension/dist/background'), + cssCodeSplit: false, + emptyOutDir: false, + sourcemap: isDev ? 'inline' : false, + terserOptions: { + mangle: false, + }, + lib: { + entry: r('src/background/main.ts'), + formats: ['cjs'], + }, + rollupOptions: { + output: { + entryFileNames: 'background.js', + extend: true, + }, + }, + }, + plugins: [ + ...sharedConfig.plugins!, + + // https://github.com/antfu/vite-plugin-windicss + WindiCSS({ + config: { + ...windiConfig, + // disable preflight to avoid css population + preflight: false, + }, + }), + ], +}) diff --git a/vite.config.content.ts b/vite.config.content.ts new file mode 100644 index 0000000..7d61981 --- /dev/null +++ b/vite.config.content.ts @@ -0,0 +1,44 @@ +import { defineConfig } from 'vite' +import WindiCSS from 'vite-plugin-windicss' +import { sharedConfig } from './vite.config' +import { isDev, r } from './scripts/utils' +import windiConfig from './windi.config' +import packageJson from './package.json' + +// bundling the content script using Vite +export default defineConfig({ + ...sharedConfig, + build: { + watch: isDev + ? {} + : undefined, + outDir: r('extension/dist/contentScripts'), + cssCodeSplit: false, + emptyOutDir: false, + sourcemap: isDev ? 'inline' : false, + lib: { + entry: r('src/contentScripts/index.ts'), + name: packageJson.name, + formats: ['iife'], + }, + rollupOptions: { + output: { + entryFileNames: 'index.global.js', + format: 'iife', + extend: true, + }, + }, + }, + plugins: [ + ...sharedConfig.plugins!, + + // https://github.com/antfu/vite-plugin-windicss + WindiCSS({ + config: { + ...windiConfig, + // disable preflight to avoid css population + preflight: false, + }, + }), + ], +}) diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..9d158c8 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,112 @@ +import { dirname, relative } from 'path' +import type { UserConfig } from 'vite' +import { defineConfig } from 'vite' +import Vue from '@vitejs/plugin-vue' +import Icons from 'unplugin-icons/vite' +import IconsResolver from 'unplugin-icons/resolver' +import Components from 'unplugin-vue-components/vite' +import AutoImport from 'unplugin-auto-import/vite' +import WindiCSS from 'vite-plugin-windicss' +import windiConfig from './windi.config' +import { isDev, port, r } from './scripts/utils' + +export const sharedConfig: UserConfig = { + root: r('src'), + resolve: { + alias: { + '~/': `${r('src')}/`, + }, + }, + define: { + __DEV__: isDev, + }, + plugins: [ + Vue(), + + AutoImport({ + imports: [ + 'vue', + { + 'webextension-polyfill': [ + ['*', 'browser'], + ], + }, + ], + dts: r('src/auto-imports.d.ts'), + }), + + // https://github.com/antfu/unplugin-vue-components + Components({ + dirs: [r('src/components')], + // generate `components.d.ts` for ts support with Volar + dts: true, + resolvers: [ + // auto import icons + IconsResolver({ + componentPrefix: '', + }), + ], + }), + + // https://github.com/antfu/unplugin-icons + Icons(), + + // rewrite assets to use relative path + { + name: 'assets-rewrite', + enforce: 'post', + apply: 'build', + transformIndexHtml(html, { path }) { + return html.replace(/"\/assets\//g, `"${relative(dirname(path), '/assets')}/`) + }, + }, + ], + optimizeDeps: { + include: [ + 'vue', + '@vueuse/core', + 'webextension-polyfill', + ], + exclude: [ + 'vue-demi', + ], + }, +} + +export default defineConfig(({ command }) => ({ + ...sharedConfig, + base: command === 'serve' ? `http://localhost:${port}/` : '/dist/', + server: { + port, + hmr: { + host: 'localhost', + }, + }, + build: { + watch: isDev + ? {} + : undefined, + outDir: r('extension/dist'), + emptyOutDir: false, + sourcemap: isDev ? 'inline' : false, + // https://developer.chrome.com/docs/webstore/program_policies/#:~:text=Code%20Readability%20Requirements + terserOptions: { + mangle: false, + }, + rollupOptions: { + input: { + // background: r('src/background/index.html'), + options: r('src/options/index.html'), + popup: r('src/popup/index.html'), + }, + }, + }, + plugins: [ + ...sharedConfig.plugins!, + + // https://github.com/antfu/vite-plugin-windicss + WindiCSS({ + config: windiConfig, + }), + ], +})) diff --git a/windi.config.ts b/windi.config.ts new file mode 100644 index 0000000..c8d8ca7 --- /dev/null +++ b/windi.config.ts @@ -0,0 +1,13 @@ +import { resolve } from 'path' +import { defineConfig } from 'windicss/helpers' + +export default defineConfig({ + darkMode: 'class', + // https://windicss.org/posts/v30.html#attributify-mode + attributify: true, + extract: { + include: [ + resolve(__dirname, 'src/**/*.{vue,html}'), + ], + }, +})