Initial commit

This commit is contained in:
Aditya Gupta
2026-06-29 19:29:19 +05:30
committed by GitHub
commit aabb8986aa
292 changed files with 17976 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
import { readFileSync } from 'node:fs';
import type { ManifestType } from '@extension/shared';
const packageJson = JSON.parse(readFileSync('./package.json', 'utf8'));
/**
* @prop default_locale
* if you want to support multiple languages, you can use the following reference
* https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization
*
* @prop browser_specific_settings
* Must be unique to your extension to upload to addons.mozilla.org
* (you can delete if you only want a chrome extension)
*
* @prop permissions
* Firefox doesn't support sidePanel (It will be deleted in manifest parser)
*
* @prop content_scripts
* css: ['content.css'], // public folder
*/
const manifest = {
manifest_version: 3,
default_locale: 'en',
name: '__MSG_extensionName__',
browser_specific_settings: {
gecko: {
id: 'example@example.com',
strict_min_version: '109.0',
},
},
version: packageJson.version,
description: '__MSG_extensionDescription__',
host_permissions: ['<all_urls>'],
permissions: ['storage', 'scripting', 'tabs', 'notifications', 'sidePanel'],
options_page: 'options/index.html',
background: {
service_worker: 'background.js',
type: 'module',
},
action: {
default_popup: 'popup/index.html',
default_icon: 'icon-34.png',
},
chrome_url_overrides: {
newtab: 'new-tab/index.html',
},
icons: {
'128': 'icon-128.png',
},
content_scripts: [
{
matches: ['http://*/*', 'https://*/*', '<all_urls>'],
js: ['content/all.iife.js'],
},
{
matches: ['https://example.com/*'],
js: ['content/example.iife.js'],
},
{
matches: ['http://*/*', 'https://*/*', '<all_urls>'],
js: ['content-ui/all.iife.js'],
},
{
matches: ['https://example.com/*'],
js: ['content-ui/example.iife.js'],
},
{
matches: ['http://*/*', 'https://*/*', '<all_urls>'],
css: ['content.css'],
},
],
devtools_page: 'devtools/index.html',
web_accessible_resources: [
{
resources: ['*.js', '*.css', '*.svg', 'icon-128.png', 'icon-34.png'],
matches: ['*://*/*'],
},
],
side_panel: {
default_path: 'side-panel/index.html',
},
} satisfies ManifestType;
export default manifest;

View File

@@ -0,0 +1,36 @@
{
"name": "chrome-extension",
"version": "0.5.0",
"description": "chrome extension - core settings",
"type": "module",
"private": true,
"sideEffects": false,
"scripts": {
"clean:node_modules": "pnpx rimraf node_modules",
"clean:turbo": "rimraf .turbo",
"clean": "pnpm clean:turbo && pnpm clean:node_modules",
"ready": "tsc -b pre-build.tsconfig.json",
"build": "vite build",
"dev": "vite build --mode development",
"test": "vitest run",
"lint": "eslint .",
"lint:fix": "pnpm lint --fix",
"prettier": "prettier . --write --ignore-path ../.prettierignore",
"type-check": "tsc --noEmit"
},
"dependencies": {
"@extension/env": "workspace:*",
"@extension/shared": "workspace:*",
"@extension/storage": "workspace:*",
"webextension-polyfill": "^0.12.0"
},
"devDependencies": {
"@extension/dev-utils": "workspace:*",
"@extension/hmr": "workspace:*",
"@extension/tsconfig": "workspace:*",
"@extension/vite-config": "workspace:*",
"@laynezh/vite-plugin-lib-assets": "^1.1.0",
"magic-string": "^0.30.17",
"ts-loader": "^9.5.2"
}
}

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./",
"noEmit": false
},
"include": ["manifest.ts"],
"exclude": [""]
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,9 @@
import 'webextension-polyfill';
import { exampleThemeStorage } from '@extension/storage';
exampleThemeStorage.get().then(theme => {
console.log('theme', theme);
});
console.log('Background loaded');
console.log("Edit 'chrome-extension/src/background/index.ts' and save to reload.");

View File

@@ -0,0 +1,10 @@
{
"extends": "@extension/tsconfig/app",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
}
},
"include": ["src", "utils", "vite.config.mts", "manifest.ts", "../node_modules/@types"]
}

View File

@@ -0,0 +1,83 @@
import { ManifestParser } from '@extension/dev-utils';
import { IS_DEV, IS_FIREFOX } from '@extension/env';
import { colorfulLog } from '@extension/shared';
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { platform } from 'node:process';
import { pathToFileURL } from 'node:url';
import type { ManifestType } from '@extension/shared';
import type { PluginOption } from 'vite';
const manifestFile = resolve(import.meta.dirname, '..', '..', 'manifest.js');
const refreshFilePath = resolve(
import.meta.dirname,
'..',
'..',
'..',
'packages',
'hmr',
'dist',
'lib',
'injections',
'refresh.js',
);
const withHMRId = (code: string) => `(function() {let __HMR_ID = 'chrome-extension-hmr';${code}\n})();`;
const getManifestWithCacheBurst = async () => {
const withCacheBurst = (path: string) => `${path}?${Date.now().toString()}`;
/**
* In Windows, import() doesn't work without file:// protocol.
* So, we need to convert path to file:// protocol. (url.pathToFileURL)
*/
if (platform === 'win32') {
return (await import(withCacheBurst(pathToFileURL(manifestFile).href))).default;
} else {
return (await import(withCacheBurst(manifestFile))).default;
}
};
const addRefreshContentScript = (manifest: ManifestType) => {
manifest.content_scripts = manifest.content_scripts || [];
manifest.content_scripts.push({
matches: ['http://*/*', 'https://*/*', '<all_urls>'],
js: ['refresh.js'], // for public's HMR(refresh) support
});
};
export default (config: { outDir: string }): PluginOption => {
const makeManifest = (manifest: ManifestType, to: string) => {
if (!existsSync(to)) {
mkdirSync(to);
}
const manifestPath = resolve(to, 'manifest.json');
if (IS_DEV) {
addRefreshContentScript(manifest);
}
writeFileSync(manifestPath, ManifestParser.convertManifestToString(manifest, IS_FIREFOX));
const refreshFileString = readFileSync(refreshFilePath, 'utf-8');
if (IS_DEV) {
writeFileSync(resolve(to, 'refresh.js'), withHMRId(refreshFileString));
}
colorfulLog(`Manifest file copy complete: ${manifestPath}`, 'success');
};
return {
name: 'make-manifest',
buildStart() {
this.addWatchFile(manifestFile);
},
async writeBundle() {
const outDir = config.outDir;
const manifest = await getManifestWithCacheBurst();
makeManifest(manifest, outDir);
},
};
};

View File

@@ -0,0 +1,52 @@
import { resolve } from 'node:path';
import { defineConfig, type PluginOption } from 'vite';
import libAssetsPlugin from '@laynezh/vite-plugin-lib-assets';
import makeManifestPlugin from './utils/plugins/make-manifest-plugin.js';
import { watchPublicPlugin, watchRebuildPlugin } from '@extension/hmr';
import { watchOption } from '@extension/vite-config';
import env, { IS_DEV, IS_PROD } from '@extension/env';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
const rootDir = resolve(import.meta.dirname);
const srcDir = resolve(rootDir, 'src');
const outDir = resolve(rootDir, '..', 'dist');
export default defineConfig({
define: {
'process.env': env,
},
resolve: {
alias: {
'@root': rootDir,
'@src': srcDir,
'@assets': resolve(srcDir, 'assets'),
},
},
plugins: [
libAssetsPlugin({
outputPath: outDir,
}) as PluginOption,
watchPublicPlugin(),
makeManifestPlugin({ outDir }),
IS_DEV && watchRebuildPlugin({ reload: true, id: 'chrome-extension-hmr' }),
nodePolyfills(),
],
publicDir: resolve(rootDir, 'public'),
build: {
lib: {
name: 'BackgroundScript',
fileName: 'background',
formats: ['es'],
entry: resolve(srcDir, 'background', 'index.ts'),
},
outDir,
emptyOutDir: false,
sourcemap: IS_DEV,
minify: IS_PROD,
reportCompressedSize: IS_PROD,
watch: watchOption,
rollupOptions: {
external: ['chrome'],
},
},
});