Compare commits

...

6 Commits

Author SHA1 Message Date
GitHub Actions 10fba3de49 chore(release): v0.1.3 2023-07-11 22:54:00 +00:00
Aaron aa16014650 feat: Add tsconfig path aliases (#32) 2023-07-11 17:39:13 -05:00
Aaron Klinker 0ce7c9d183 chore: Upgrade to pnpm 8 2023-07-11 17:35:45 -05:00
Aaron Klinker ac0b28e608 fix: Cleanup build summary with sourcemaps 2023-07-11 17:18:22 -05:00
Aaron 80fed4a451 docs: Create documentation site (#31) 2023-07-11 14:22:47 -05:00
Aaron Klinker 05ca9985d5 fix: Merge manifest option from both inline and user config 2023-07-11 10:24:55 -05:00
26 changed files with 2369 additions and 978 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: Setup PNPM
uses: pnpm/action-setup@v2
with:
version: 7
version: 8
- name: Setup NodeJS
uses: actions/setup-node@v3
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- name: Setup PNPM
uses: pnpm/action-setup@v2
with:
version: 7
version: 8
- name: Setup NodeJS
uses: actions/setup-node@v3
-1
View File
@@ -1,2 +1 @@
ignore-workspace-root-check=true
use-node-version=18.16.0
+26
View File
@@ -1,5 +1,31 @@
# Changelog
## v0.1.3
[compare changes](https://github.com/aklinker1/wxt/compare/v0.1.2...v0.1.3)
### 🚀 Enhancements
- Add tsconfig path aliases ([#32](https://github.com/aklinker1/wxt/pull/32))
### 🩹 Fixes
- Merge `manifest` option from both inline and user config ([05ca998](https://github.com/aklinker1/wxt/commit/05ca998))
- Cleanup build summary with sourcemaps ([ac0b28e](https://github.com/aklinker1/wxt/commit/ac0b28e))
### 📖 Documentation
- Create documentation site ([#31](https://github.com/aklinker1/wxt/pull/31))
### 🏡 Chore
- Upgrade to pnpm 8 ([0ce7c9d](https://github.com/aklinker1/wxt/commit/0ce7c9d))
### ❤️ Contributors
- Aaron
- Aaron Klinker
## v0.1.2
[compare changes](https://github.com/aklinker1/wxt/compare/v0.1.1...v0.1.2)
+3 -3
View File
@@ -2,21 +2,21 @@
<p align="center"><i>Next gen framework for developing web extensions.<br/>Powered by <a href="https://vitejs.dev/" target="_blank">Vite</a>. Inspired by <a href="https://nuxt.com/" target="_blank">Nuxt</a>.</i></p>
![Example CLI Output](./.github/assets/cli-output.png)
![Example CLI Output](./docs/assets/cli-output.png)
## Features
- 🌐 Supports all browsers
- ✅ Supports both MV2 and MV3
- 📂 Directory based entrypoints
- ⚡ Dev mode with HMR & auto-reload
- 📂 File based entrypoints
- 🚔 TypeScript
- 🦾 Auto-imports
- ⬇️ Download and bundle remote URL imports
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
### Todo
- 🎨 Frontend framework agnostic: works with Vue, React, Svelte, etc
- 🖍️ Quickly bootstrap a new project
- 📏 Bundle analysis
- 🤖 Automated publishing
+35
View File
@@ -0,0 +1,35 @@
import { defineConfig } from 'vitepress';
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: 'WXT',
description: 'Next gen framework for developing web extensions',
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: 'Get Started', link: '/get-started/installation.md' },
{ text: 'Guide', link: '/guide.md' },
{ text: 'API', link: '/api.md' },
],
sidebar: {
'/get-started/': [
{
text: 'Guide',
items: [
{ text: 'Introduction', link: '/get-started/introduction.md' },
{ text: 'Installation', link: '/get-started/installation.md' },
{ text: 'Configuration', link: '/get-started/configuration.md' },
{ text: 'Entrypoints', link: '/get-started/entrypoints.md' },
{ text: 'Assets', link: '/get-started/assets.md' },
{ text: 'Build Targets', link: '/get-started/build-targets.md' },
{ text: 'Publishing', link: '/get-started/publishing.md' },
{ text: 'Testing', link: '/get-started/testing.md' },
],
},
],
},
socialLinks: [{ icon: 'github', link: 'https://github.com/aklinker1/wxt' }],
},
});
+5
View File
@@ -0,0 +1,5 @@
# API Reference
:::warning 🚧&ensp;Under construction
This documentation does not exist yet.
:::

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

+85
View File
@@ -0,0 +1,85 @@
# Assets
WXT has two directories for storing assets like CSS, images, or fonts.
- `<srcDir>/public`: Store files that will be copied into the output directory as-is
- `<srcDir>/assets`: Store files that will be processed by Vite during the build process
## `/public` Directory
Place static files like the extension icon or `_locales/` directory here. These files will be copied over to the output directory without being transformed by Vite.
```
<srcDir>
└─ public/
├─ icon-16.png
├─ icon-32.png
├─ icon-48.png
├─ icon-96.png
└─ icon-128.png
```
### Example
You can reference these files by using absolute paths in HTML files or `browser.runtime.getURL` in content scripts.
:::code-group
```html [popup.html]
<img src="/icon-128.png" />
```
```ts [content.ts]
defineContentScript({
main() {
const image = document.createElement('img');
image.src = browser.runtime.getURL('/icon-128.png');
document.body.append(image);
},
});
```
:::
## `/assets` Directory
Files in the assets directory will be processed by Vite. They are imported in your source code, and will be transformed or renamed in the output directory.
```
<srcDir>
└─ assets/
├─ style.css
└─ illustration.svg
```
### Example
:::code-group
```html [popup.html]
<html>
<head>
<link rel="stylesheet" href="~/assets/style.css" />
<!-- ... -->
</head>
<body>
<img src="~/illustration.svg" />
<!-- ... -->
</body>
</html>
```
```ts [content.ts]
import '~/assets/style.css';
import illustration from '~/assets/style.svg';
defineContentScript({
main() {
const image = document.createElement('img');
image.src = illustration;
document.body.append(image);
},
});
```
:::
+46
View File
@@ -0,0 +1,46 @@
# Build Targets
You can build an extension for any combination of browser and manifest verison. Different browsers and manifest versions support different APIs and entrypoints, so be sure to check that your extension functions as expected for each target.
Separate build targets are to separate output directories:
```
<root>
└─ .output
├─ chrome-mv3
├─ firefox-mv2
├─ edge-mv3
└─ ...
```
## Target Browser
To build for a specific browser, pass the `-b --browser` flag from the CLI:
```
wxt --browser firefox
wxt build --browser firefox
```
By default, it will build for `chrome`. When excluding the [`--mv2` or `--mv3` flags](#target-manifest-version), it will default to the commonly accepted version used with that browser.
| Browser | Default Manifest Version |
| ---------------- | :----------------------: |
| `chrome` | 3 |
| `firefox` | 2 |
| `safari` | 2 |
| `edge` | 3 |
| Any other string | 3 |
## Target Manifest Version
To build for a specific manifest version, pass either the `--mv2` flag or `--mv3` flag from the CLI.
```sh
wxt --mv2
wxt build --mv2
```
When the `-b --browser` flag is not passed, it defaults to `chrome`. So here, we're targetting MV2 for Chrome.
+62
View File
@@ -0,0 +1,62 @@
# Configuration
WXT's behavior can be configured via the `wxt.config.ts` file. In this file, you can add Vite plugins, change the directory strucutre of your project, and provide permissions or other fields to the `<outdir>/manifest.json`.
However, since WXT is an opinionated framework, some things cannot be configured.
## Config File
To configure WXT, create a `wxt.config.ts` file in your project root. It should have the following contents:
```ts
import { defineConfig } from 'wxt';
export default defineConfig({
// My WXT config
});
```
:::info
See the [API reference](/api.md) for a full list of options.
:::
## Directory Config
WXT allows you to edit several directories to your liking:
- `root` (default: `process.cwd()`) - Root of the WXT project
- `srcDir` (default: `<root>`) - Location of all your source code
- `entrypointsDir` (default: `<srcDir>/entrypoints`) - Folder containing all the entrypoints.
- `publicDir` (default: `<srcDir>/public`) - Folder containing [public assets](/get-started/assets.md)
### Example
If you want a `src/` directory to contain all your source code, and you want to rename `entrypoints/` to `entries/`, your config would look like this:
```ts
import { defineConfig } from 'wxt';
export default defineConfig({
srcDir: 'src',
entrypointsDir: 'entries',
});
```
## Vite Config
Vite is the bundler used to build each part of an extension. Vite can be configured via the `vite` option.
### Example
A common reason to configure Vite is to add plugins:
```ts
import { defineConfig } from 'wxt';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
vite: {
plugins: [vue()],
},
});
```
+89
View File
@@ -0,0 +1,89 @@
# Defining Entrypoints
Entrypoints are any HTML, JS, or CSS file that needs to be bundled and included with the extension.
They may or may not be listed in the extension's `manifest.json`.
## `/entrypoints` Directory
In WXT, entrypoints are defined by adding a file to the `entrypoints/` directory.
For example, a project that looks like this:
```
<root>
├─ entrypoints/
│ ├─ background.ts
│ ├─ content.ts
│ ├─ injected.ts
│ └─ popup.html
└─ wxt.config.ts
```
would result in the following `manifest.json`:
```json
{
// ...
"manifest_version": 3,
"action": {
// ...
"default_popup": "popup.html"
},
"background": {
// ...
"service_worker": "background.js"
},
"content_scripts": [
{
// ...
"js": ["content-scripts/content.js"]
}
]
}
```
If a file uses a [special name recognized by WXT](/get-started/entrypoints.md), it will be added to the manifest. In this case:
- `popup.html` &rarr; `action.default_popup`
- `content.ts` &rarr; `content_scripts.*.js`
- `background.ts` &rarr; `background.service_worker`
But not all entrypoints are added to the `manifest.json`. If they have a name that is not recognized by WXT, they are still built and included in the extension, but they are unlisted and do not show up in the manifest.
In this case, `injected.ts` gets bundled to `<outdir>/injected.js` and is accessible via `browser.runtime.getURL("/injected.js")`.
:::info
See [`/entrypoints` folder](/get-started/entrypoints.md) documentation for a full list of recognized entrypoint filenames.
:::
## Entrypoint Options
Some entrypoints, like content scripts, actions, or the background, can recieve additional options.
In HTML files, options are listed as `meta` tags:
```html
<html>
<head>
<!-- Defining the popup's "default_icon" field -->
<meta name="manifest.default_icon" content="{ '16': '/icon/16.png' }" />
</head>
</html>
```
In TS files, options are apart of the file's default export:
```ts
export default defineContentScript({
matches: ['*://*.google.com/*'],
runAt: 'document_start',
main() {
// ...
},
});
```
:::info
For a full list of entrypoints and each of their options, see the [`/entrypoints` folder](/get-started/entrypoints.md) documentation.
:::
+98
View File
@@ -0,0 +1,98 @@
# Installation
Bootstrap a new project or start from scratch.
## Bootstrap Project
:::warning 🚧&ensp;This feature is not implemented yet!
See [From Scratch](#from-scratch) instead.
:::
:::code-group
```sh [pnpm]
pnpx wxt@latest init <project-name>
```
```sh [npm]
npx wxt@latest init <project-name>
```
:::
## From Scratch
Create a new NPM project:
:::code-group
```sh [pnpm]
pnpm init <project-name>
cd <project-name>
echo 'shamefully-hoist=true' >> .npmrc
```
```sh [npm]
npm init <project-name>
cd <project-name>
```
```sh [yarn]
yarn init <project-name>
cd <project-name>
```
:::
Then install `wxt`:
:::code-group
```sh [pnpm]
pnpm add wxt
```
```sh [npm]
npm i --save wxt
```
```sh [yarn]
yarn add wxt
```
:::
Finally, add `package.json` scripts:
```json
{
"scripts": {
"dev": "wxt",
"dev:firefox": "wxt --browser firefox",
"build": "wxt build",
"build:firefox": "wxt build --browser firefox"
}
}
```
## Development
Once you've installed WXT, you can start the development server using the `dev` command:
```sh
pnpm dev
```
:::tip 🎉&ensp;Well done!
The dev command will build the extension for development, open the browser, and reload the different parts of the extension when you save changes.
:::
## Next Steps
Now that your WXT project is setup, you're ready to build a out your web extension!
- Learn how to [add entrypoints](./entrypoints.md) like the popup, background, or content scripts
- [Configure WXT](./configuration.md) by creating a `wxt.config.ts` file
+32
View File
@@ -0,0 +1,32 @@
# Introduction
WXT is a free and open source framework for building web extensions in an conventional, intuative, and safe way **_for all browsers_**.
WXT comes with full TypeScript support and auto-imports. Sounds familiar? That's right, **_WXT was based off of Nuxt_** and aims to provide the same greate DX and features.
![Example build output](../assets/cli-output.png)
## Conventions
WXT is an optionated framework. This helps keep projects consistent and easy to pick up.
- **Generated manifest**: Based on your project's file structure
- **Entrypoint configuration**: Configure entrypoints from the same file they're declare in
- **Type-safety is a priority**: Out-of-the-box TypeScript support with improved browser API typing
- **Simple output file structure**: Ouptut file paths minimize the path at runtime
## Development
WXT's dev server supports modern features like HMR to provide a lighting fast dev mode.
When changes can't be hot-reloaded, like content scripts or background scripts, they're reloaded individually to prevent reloading the entire extension and slowing down your development cycle.
## Production-ready
Production builds are optimized for store review, changing as few files as possible between builds.
In addition, WXT fully supports Firefox's source code requirements when using a bundler. It will automatically create and upload a ZIP file of your source code.
:::info
See [Publishing](./publishing.md) for more info around production builds.
:::
+5
View File
@@ -0,0 +1,5 @@
# Publishing
:::warning 🚧&ensp;Not implemented yet!
For now, manually zip the output directory and upload to stores by hand.
:::
+5
View File
@@ -0,0 +1,5 @@
# Testing
:::warning 🚧&ensp;Testing utils are not implemented yet!
Eventually, the plan is to have an integration with Vitest.
:::
+5
View File
@@ -0,0 +1,5 @@
# Guide
:::warning 🚧&ensp;Under construction
This documentation does not exist yet.
:::
+49
View File
@@ -0,0 +1,49 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
titleTemplate: 'Next Generation Web Extension Framework'
hero:
name: WXT
text: Next gen framework for web extensions
tagline: Powered by Vite, inspired by Nuxt.
actions:
- theme: brand
text: Get Started
link: /get-started/installation
- theme: alt
text: Learn More
link: /get-started/introduction
features:
- icon: 🌐
title: Supported Browsers
details: Chrome, Firefox, Edge, Safari, and any Chromium based browser.
- icon: ✅
title: MV2 and MV3
details: Supports both manifest versions for each browser.
- icon: ⚡
title: Fast Dev Mode
details: HMR for UIs and fast reload for background and content scripts.
- icon: 📂
title: File Based Entrypoints
details: Manifest is generated based on files inside the project.
- icon: 🚔
title: TypeScript
details: Scale projects with full TS support.
- icon: 🦾
title: Auto-imports
details: Nuxt-like auto-imports to speed up development.
- icon: ⬇️
title: Bundle Remote Code
details: Downloads and bundles remote code imported from URLs.
- icon: 🎨
title: Frontend framework agnostic
details: Works with any front-end framework with a Vite plugin.
- icon: 🤖
title: Automated Publishing
details: 'TODO: Automatically zip, upload, and release extensions.'
- icon: 📏
title: Bundle analysis
details: 'TODO: Tools for analyizing the final extension bundle.'
---
+13 -8
View File
@@ -56,18 +56,23 @@ describe('User Config', () => {
`);
});
it('should accept a function for a manifest', async () => {
it('should merge inline and user config based manifests', async () => {
const project = new TestProject();
project.addFile(
'wxt.config.ts',
`import { defineConfig } from 'wxt';
export default defineConfig({
manifest: ({ mode, browser }) => ({
// @ts-expect-error
example_customization: [mode, browser],
})
})`,
);
await project.build({
// @ts-expect-error: Specifically setting an invalid field for the test - it should show up in the snapshot
manifest: ({ mode, browser, manifestVersion, command }) => ({
example_customization: [
mode,
browser,
String(manifestVersion),
command,
],
manifest: ({ manifestVersion, command }) => ({
example_customization: [String(manifestVersion), command],
}),
});
+8 -9
View File
@@ -55,6 +55,7 @@ export class TestProject {
*/
addFile(filename: string, content?: string) {
this.files.push([filename, content ?? '']);
if (filename === 'wxt.config.ts') this.config = {};
}
/**
@@ -63,15 +64,13 @@ export class TestProject {
async build(config: InlineConfig = {}) {
if (this.config == null) this.setConfigFileConfig();
await Promise.all(
this.files.map(async (file) => {
const [name, content] = file;
const filePath = resolve(this.root, name);
const fileDir = dirname(filePath);
await fs.ensureDir(fileDir);
await fs.writeFile(filePath, content ?? '', 'utf-8');
}),
);
for (const file of this.files) {
const [name, content] = file;
const filePath = resolve(this.root, name);
const fileDir = dirname(filePath);
await fs.ensureDir(fileDir);
await fs.writeFile(filePath, content ?? '', 'utf-8');
}
execSync('npm i --ignore-scripts', { cwd: this.root });
await build({ ...config, root: this.root });
+21 -2
View File
@@ -1,8 +1,12 @@
{
"name": "wxt",
"type": "module",
"version": "0.1.2",
"version": "0.1.3",
"description": "Next gen framework for developing web extensions",
"engines": {
"node": ">=18.16.0",
"pnpm": ">=8"
},
"repository": {
"type": "git",
"url": "https://github.com/aklinker1/wxt"
@@ -49,7 +53,10 @@
"test": "vitest",
"test:coverage": "vitest run --coverage",
"prepare": "simple-git-hooks",
"prepublish": "pnpm -s build"
"prepublish": "pnpm -s build",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
"dependencies": {
"@types/webextension-polyfill": "^0.10.0",
@@ -88,6 +95,7 @@
"tsup": "^7.0.0",
"tsx": "^3.12.7",
"typescript": "^5.1.3",
"vitepress": "1.0.0-beta.5",
"vitest": "^0.32.4",
"vitest-mock-extended": "^1.1.4",
"webextension-polyfill": "^0.10.0"
@@ -98,5 +106,16 @@
"packageManager": "pnpm@8.6.3",
"simple-git-hooks": {
"pre-commit": "pnpm pretty-quick --staged"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"search-insights"
],
"allowAny": [
"node-fetch"
]
}
}
}
+1716 -930
View File
File diff suppressed because it is too large Load Diff
+14 -1
View File
@@ -129,7 +129,20 @@ async function writeTsConfigFile(
"strict": true,
/* Completeness */
"skipLibCheck": true
"skipLibCheck": true,
/* Aliases */
"baseUrl": "${relative(dir, config.root)}",
"paths": {
"@@": ["."],
"@@/*": ["./*"],
"~~": ["."],
"~~/*": ["./*"],
"@": ["${relative(config.root, config.srcDir)}"],
"@/*": ["${relative(config.root, config.srcDir)}/*"],
"~": ["${relative(config.root, config.srcDir)}"],
"~/*": ["${relative(config.root, config.srcDir)}/*"]
}
},
"include": [
"${relative(dir, config.root)}/**/*",
+20 -11
View File
@@ -1,4 +1,4 @@
import path, { extname, relative, resolve } from 'path';
import path, { relative, resolve } from 'path';
import { BuildOutput, InternalConfig } from '../types';
import { printTable } from './printTable';
import pc from 'picocolors';
@@ -13,14 +13,8 @@ export async function printBuildSummary(
...output.steps.flatMap((step) => step.chunks),
...output.publicAssets,
].sort((l, r) => {
const lWeight =
CHUNK_SORT_WEIGHTS[l.fileName] ??
CHUNK_SORT_WEIGHTS[extname(l.fileName)] ??
DEFAULT_SORT_WEIGHT;
const rWeight =
CHUNK_SORT_WEIGHTS[r.fileName] ??
CHUNK_SORT_WEIGHTS[extname(r.fileName)] ??
DEFAULT_SORT_WEIGHT;
const lWeight = getChunkSortWeight(l.fileName);
const rWeight = getChunkSortWeight(r.fileName);
const diff = lWeight - rWeight;
if (diff !== 0) return diff;
return l.fileName.localeCompare(r.fileName);
@@ -34,9 +28,8 @@ export async function printBuildSummary(
relative(process.cwd(), config.outDir) + path.sep,
chunk.fileName,
];
const ext = extname(chunk.fileName);
const prefix = i === chunks.length - 1 ? ' └─' : ' ├─';
const color = CHUNK_COLORS[ext] ?? DEFAULT_COLOR;
const color = getChunkColor(chunk.fileName);
const stats = await fs.lstat(resolve(config.outDir, chunk.fileName));
totalSize += stats.size;
const size = String(filesize(stats.size));
@@ -58,13 +51,29 @@ const DEFAULT_SORT_WEIGHT = 100;
const CHUNK_SORT_WEIGHTS: Record<string, number> = {
'manifest.json': 0,
'.html': 1,
'.js.map': 2,
'.js': 2,
'.css': 3,
};
function getChunkSortWeight(filename: string) {
return (
Object.entries(CHUNK_SORT_WEIGHTS).find(([key, value]) => {
if (filename.endsWith(key)) return value;
})?.[1] ?? DEFAULT_SORT_WEIGHT
);
}
const DEFAULT_COLOR = pc.blue;
const CHUNK_COLORS: Record<string, (text: string) => string> = {
'.js.map': pc.gray,
'.html': pc.green,
'.css': pc.magenta,
'.js': pc.cyan,
};
function getChunkColor(filename: string) {
return (
Object.entries(CHUNK_COLORS).find(([key, value]) => {
if (filename.endsWith(key)) return value;
})?.[1] ?? DEFAULT_COLOR
);
}
+25 -11
View File
@@ -1,9 +1,11 @@
import {
ConfigEnv,
ExtensionRunnerConfig,
InlineConfig,
InternalConfig,
UserConfig,
UserManifest,
UserManifestFn,
} from '../types';
import path, { resolve } from 'node:path';
import * as vite from 'vite';
@@ -32,15 +34,6 @@ export async function getInternalConfig(
const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
const logger = config.logger ?? consola;
const manifest: UserManifest = await (typeof config.manifest === 'function'
? config.manifest({
browser,
command,
manifestVersion,
mode,
})
: config.manifest ?? {});
const baseConfig: InternalConfigNoUserDirs = {
root,
outDir,
@@ -52,7 +45,6 @@ export async function getInternalConfig(
command,
logger,
vite: config.vite ?? {},
manifest,
imports: config.imports ?? {},
runnerConfig: await loadConfig<ExtensionRunnerConfig>({
name: 'web-ext',
@@ -92,6 +84,12 @@ export async function getInternalConfig(
const wxtDir = resolve(srcDir, '.wxt');
const typesDir = resolve(wxtDir, 'types');
// Merge manifest sources
const env: ConfigEnv = { mode, browser, manifestVersion, command };
const userManifest = await resolveManifestConfig(env, userConfig.manifest);
const inlineManifest = await resolveManifestConfig(env, config.manifest);
const manifest = vite.mergeConfig(userManifest, inlineManifest);
const finalConfig: InternalConfig = {
...merged,
srcDir,
@@ -100,6 +98,7 @@ export async function getInternalConfig(
wxtDir: wxtDir,
typesDir,
fsCache: createFsCache(wxtDir),
manifest,
};
// Customize the default vite config
@@ -137,5 +136,20 @@ export async function getInternalConfig(
*/
type InternalConfigNoUserDirs = Omit<
InternalConfig,
'srcDir' | 'publicDir' | 'entrypointsDir' | 'wxtDir' | 'typesDir' | 'fsCache'
| 'srcDir'
| 'publicDir'
| 'entrypointsDir'
| 'wxtDir'
| 'typesDir'
| 'fsCache'
| 'manifest'
>;
async function resolveManifestConfig(
env: ConfigEnv,
manifest: UserManifest | Promise<UserManifest> | UserManifestFn | undefined,
): Promise<UserManifest> {
return await (typeof manifest === 'function'
? manifest(env)
: manifest ?? {});
}
+5
View File
@@ -0,0 +1,5 @@
{
"github": {
"silent": true
}
}