Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f82645c08 | |||
| d200c376f8 | |||
| b58fb02016 | |||
| e1bab6c746 |
+4
-2
@@ -2,5 +2,7 @@ coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 80%
|
||||
threshold: 1%
|
||||
informational: true
|
||||
patch:
|
||||
default:
|
||||
informational: true
|
||||
|
||||
@@ -13,3 +13,4 @@ CHANGELOG.md
|
||||
*.txt
|
||||
_gitignore
|
||||
_redirects
|
||||
*.svelte
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## v0.7.4
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.7.3...v0.7.4)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Support `react-refresh` when pre-rendering HTML pages in dev mode ([#158](https://github.com/wxt-dev/wxt/pull/158))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Add migration guides ([b58fb02](https://github.com/wxt-dev/wxt/commit/b58fb02))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Upgrade templates to v0.7 ([#156](https://github.com/wxt-dev/wxt/pull/156))
|
||||
|
||||
## v0.7.3
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.7.2...v0.7.3)
|
||||
|
||||
@@ -80,6 +80,12 @@ export default defineConfig({
|
||||
{ text: 'Development', link: '/guide/development.md' },
|
||||
{ text: 'Testing', link: '/guide/testing.md' },
|
||||
{ text: 'Vite', link: '/guide/vite.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Other',
|
||||
items: [
|
||||
{ text: 'Migrate to WXT', link: '/guide/migrate-to-wxt.md' },
|
||||
{ text: 'Compare', link: '/guide/compare.md' },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Installation
|
||||
|
||||
Bootstrap a new project, start from scratch, or migrate an existing project.
|
||||
Bootstrap a new project, start from scratch, or [migrate an existing project](/guide/migrate-to-wxt).
|
||||
|
||||
## Bootstrap Project
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# Migrate to WXT
|
||||
|
||||
> If you have problems migrating to WXT, feel free to ask for help in GitHub by [starting a discussion](https://github.com/wxt-dev/wxt/discussions/new?category=q-a)!
|
||||
|
||||
## Overview
|
||||
|
||||
Always start by generating a new vanilla project and merging it into your project one file at a time.
|
||||
|
||||
```sh
|
||||
cd path/to/your/project
|
||||
pnpx wxt@latest init example-wxt --template vanilla
|
||||
```
|
||||
|
||||
In general, you'll need to:
|
||||
|
||||
<input type="checkbox" /> Install `wxt`<br />
|
||||
<input type="checkbox" /> Update/create `package.json` scripts to use `wxt` (don't forget about `postinstall`)<br />
|
||||
<input type="checkbox" /> Move entrypoints into `entrypoints/` directory<br />
|
||||
<input type="checkbox" /> Move assets into either the `assets/` or `public/` directories<br />
|
||||
<input type="checkbox" /> Move manifest.json content into `wxt.config.ts`<br />
|
||||
<input type="checkbox" /> Convert custom import syntax to be compatible with Vite<br />
|
||||
<input type="checkbox" /> Add a default export to JS entrypoints<br />
|
||||
<input type="checkbox" /> Use the `browser` global instead of `chrome`<br />
|
||||
<input type="checkbox" /> Compare final `manifest.json` files, making sure permissions and host permissions are unchanged<br />
|
||||
<input type="checkbox" /> Extension output by `wxt build` works the same way as before the migration<br />
|
||||
|
||||
Every project is different, so there's no one-solution-fits-all to migrating your project. Just make sure `wxt dev` runs, `wxt build` results in a working extension, and the list of permissions in the `manifest.json` hasn't changed. If all that looks good, you've finished migrating your extension!
|
||||
|
||||
## Popular Tools/Frameworks
|
||||
|
||||
Here's specific steps for other popuplar frameworks/build tools.
|
||||
|
||||
### `vite-plugin-web-extension`
|
||||
|
||||
Since you're already using Vite, it's a simple refactor.
|
||||
|
||||
1. Install `wxt`
|
||||
2. Move and refactor your entrypoints to WXT's style (with a default export)
|
||||
3. Update package.json scripts to use `wxt`
|
||||
4. Add `"postinstall": "wxt prepare"` script
|
||||
5. Move the `manifest.json` into `wxt.config.ts`
|
||||
6. Move any custom settings from `vite.config.ts` into `wxt.config.ts`'s
|
||||
7. Compare `dist/manifest.json` to `.output/*/manifest.json`, they should have the same content as before. If not, tweak your entrypoints and config to get as close as possible.
|
||||
|
||||
### `plasmo`
|
||||
|
||||
1. Install `wxt`
|
||||
2. Move entrypoints into `entrypoints/` directory, merging the named exports used to configure your JS entrypoints into WXT's default export
|
||||
3. Move public `assets/*` into the `public/` directory
|
||||
4. If you use CSUI, migrate to WXT's `createContentScriptUi`
|
||||
5. Convert Plasmo's custom import resolutions to Vite's
|
||||
6. If importing remote code via a URL, add a `url:` prefix so it works with WXT
|
||||
7. Compare your output `manifest.json` files from before the migration to after the migration. They should have the same content. If not, tweak your entrypoints and config to get as close as possible.
|
||||
@@ -60,7 +60,7 @@ Eventually, WXT will provide utilities for setting up these auto-imports. For no
|
||||
|
||||
Not all testing frameworks can handle auto-imports. If your framework or setup is not listed below, it may be easiest to disable auto-imports.
|
||||
|
||||
To setup auto-imports manually, use [`unplugin-auto-import`](https://www.npmjs.com/package/unplugin-auto-import). It uses the same tool, `unimport`, as WXT and will result in compatiple auto-imports. `unplugin-auto-import` supports lots of different tools (vite, webpage, esbuild, rollup, etc). You can try and integrate it into your build process.
|
||||
To setup auto-imports manually, use [`unplugin-auto-import`](https://www.npmjs.com/package/unplugin-auto-import). It uses the same tool, `unimport`, as WXT and will result in compatiple auto-imports. `unplugin-auto-import` supports lots of different tools (vite, webpack, esbuild, rollup, etc). You can try and integrate it into your build process.
|
||||
|
||||
### Vitest (Recommended)
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.7.3",
|
||||
"version": "0.7.4",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"engines": {
|
||||
"node": ">=18.16.0",
|
||||
|
||||
@@ -4,68 +4,147 @@ import { getEntrypointName } from '../utils/entrypoints';
|
||||
import { parseHTML } from 'linkedom';
|
||||
import { dirname, isAbsolute, relative, resolve } from 'path';
|
||||
|
||||
// Cache the preamble script for all devHtmlPrerender plugins, not just one
|
||||
let reactRefreshPreamble = '';
|
||||
|
||||
/**
|
||||
* Pre-renders the HTML entrypoints when building the extension to connect to the dev server.
|
||||
*/
|
||||
export function devHtmlPrerender(config: InternalConfig): vite.Plugin {
|
||||
return {
|
||||
apply: 'build',
|
||||
name: 'wxt:dev-html-prerender',
|
||||
config() {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@wxt/reload-html': resolve(
|
||||
config.root,
|
||||
'node_modules/wxt/dist/virtual-modules/reload-html.js',
|
||||
),
|
||||
export function devHtmlPrerender(config: InternalConfig): vite.PluginOption {
|
||||
const htmlReloadId = '@wxt/reload-html';
|
||||
const resolvedHtmlReloadId = resolve(
|
||||
config.root,
|
||||
'node_modules/wxt/dist/virtual-modules/reload-html.js',
|
||||
);
|
||||
const virtualReactRefreshId = '@wxt/virtual-react-refresh';
|
||||
const resolvedVirtualReactRefreshId = '\0' + virtualReactRefreshId;
|
||||
|
||||
return [
|
||||
{
|
||||
apply: 'build',
|
||||
name: 'wxt:dev-html-prerender',
|
||||
config() {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
[htmlReloadId]: resolvedHtmlReloadId,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
},
|
||||
// Convert scripts like src="./main.tsx" -> src="http://localhost:3000/entrypoints/popup/main.tsx"
|
||||
// before the paths are replaced with their bundled path
|
||||
transform(code, id) {
|
||||
const server = config.server;
|
||||
if (
|
||||
config.command !== 'serve' ||
|
||||
server == null ||
|
||||
!id.endsWith('.html')
|
||||
)
|
||||
return;
|
||||
|
||||
const { document } = parseHTML(code);
|
||||
|
||||
const pointToDevServer = (
|
||||
querySelector: string,
|
||||
attr: string,
|
||||
): void => {
|
||||
document.querySelectorAll(querySelector).forEach((element) => {
|
||||
const src = element.getAttribute(attr);
|
||||
if (!src) return;
|
||||
|
||||
if (isAbsolute(src)) {
|
||||
element.setAttribute(attr, server.origin + src);
|
||||
} else if (src.startsWith('.')) {
|
||||
const abs = resolve(dirname(id), src);
|
||||
const pathname = relative(config.root, abs);
|
||||
element.setAttribute(attr, `${server.origin}/${pathname}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
pointToDevServer('script[type=module]', 'src');
|
||||
pointToDevServer('link[rel=stylesheet]', 'href');
|
||||
|
||||
// Add a script to add page reloading
|
||||
const reloader = document.createElement('script');
|
||||
reloader.src = htmlReloadId;
|
||||
reloader.type = 'module';
|
||||
document.head.appendChild(reloader);
|
||||
|
||||
const newHtml = document.toString();
|
||||
config.logger.debug('transform ' + id);
|
||||
config.logger.debug('Old HTML:\n' + code);
|
||||
config.logger.debug('New HTML:\n' + newHtml);
|
||||
return newHtml;
|
||||
},
|
||||
|
||||
// Pass the HTML through the dev server to add dev-mode specific code
|
||||
async transformIndexHtml(html, ctx) {
|
||||
const server = config.server;
|
||||
if (config.command !== 'serve' || server == null) return;
|
||||
|
||||
const originalUrl = `${server.origin}${ctx.path}`;
|
||||
const name = getEntrypointName(config.entrypointsDir, ctx.filename);
|
||||
const url = `${server.origin}/${name}.html`;
|
||||
const serverHtml = await server.transformIndexHtml(
|
||||
url,
|
||||
html,
|
||||
originalUrl,
|
||||
);
|
||||
const { document } = parseHTML(serverHtml);
|
||||
|
||||
// React pages include a preamble as an unsafe-inline type="module" script to enable fast refresh, as shown here:
|
||||
// https://github.com/wxt-dev/wxt/issues/157#issuecomment-1756497616
|
||||
// Since unsafe-inline scripts are blocked by MV3 CSPs, we need to virtualize it.
|
||||
const reactRefreshScript = Array.from(
|
||||
document.querySelectorAll('script[type=module]'),
|
||||
).find((script) => script.innerHTML.includes('@react-refresh'));
|
||||
if (reactRefreshScript) {
|
||||
// Save preamble to serve from server
|
||||
reactRefreshPreamble = reactRefreshScript.innerHTML;
|
||||
|
||||
// Replace unsafe inline script
|
||||
const virtualScript = document.createElement('script');
|
||||
virtualScript.type = 'module';
|
||||
virtualScript.src = `${server.origin}/${virtualReactRefreshId}`;
|
||||
reactRefreshScript.replaceWith(virtualScript);
|
||||
}
|
||||
|
||||
// Change /@vite/client -> http://localhost:3000/@vite/client
|
||||
const viteClientScript = document.querySelector<HTMLScriptElement>(
|
||||
"script[src='/@vite/client']",
|
||||
);
|
||||
if (viteClientScript) {
|
||||
viteClientScript.src = `${server.origin}${viteClientScript.src}`;
|
||||
}
|
||||
|
||||
const newHtml = document.toString();
|
||||
config.logger.debug('transformIndexHtml ' + ctx.filename);
|
||||
config.logger.debug('Old HTML:\n' + html);
|
||||
config.logger.debug('New HTML:\n' + newHtml);
|
||||
return newHtml;
|
||||
},
|
||||
},
|
||||
async transform(html, id) {
|
||||
const server = config.server;
|
||||
if (config.command !== 'serve' || server == null || !id.endsWith('.html'))
|
||||
return;
|
||||
|
||||
const originalUrl = `${server.origin}${id}`;
|
||||
const name = getEntrypointName(config.entrypointsDir, id);
|
||||
const url = `${server.origin}/${name}.html`;
|
||||
const serverHtml = await server.transformIndexHtml(
|
||||
url,
|
||||
html,
|
||||
originalUrl,
|
||||
);
|
||||
const { document } = parseHTML(serverHtml);
|
||||
|
||||
const pointToDevServer = (querySelector: string, attr: string): void => {
|
||||
document.querySelectorAll(querySelector).forEach((element) => {
|
||||
const src = element.getAttribute(attr);
|
||||
if (!src) return;
|
||||
|
||||
if (isAbsolute(src)) {
|
||||
element.setAttribute(attr, server.origin + src);
|
||||
} else if (src.startsWith('.')) {
|
||||
const abs = resolve(dirname(id), src);
|
||||
const pathname = relative(config.root, abs);
|
||||
element.setAttribute(attr, `${server.origin}/${pathname}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
pointToDevServer('script[type=module]', 'src');
|
||||
pointToDevServer('link[rel=stylesheet]', 'href');
|
||||
|
||||
// Add a script to add page reloading
|
||||
const reloader = document.createElement('script');
|
||||
reloader.src = '@wxt/reload-html';
|
||||
reloader.type = 'module';
|
||||
document.head.appendChild(reloader);
|
||||
|
||||
const newHtml = document.toString();
|
||||
config.logger.debug('Transformed ' + id);
|
||||
config.logger.debug('Old HTML:\n' + html);
|
||||
config.logger.debug('New HTML:\n' + newHtml);
|
||||
return newHtml;
|
||||
{
|
||||
name: 'wxt:virtualize-react-refresh',
|
||||
apply: 'serve',
|
||||
resolveId(id) {
|
||||
if (id === `/${virtualReactRefreshId}`) {
|
||||
return resolvedVirtualReactRefreshId;
|
||||
}
|
||||
// Ignore chunk contents when pre-rendering
|
||||
if (id.startsWith('/chunks/')) {
|
||||
return '\0noop';
|
||||
}
|
||||
},
|
||||
load(id) {
|
||||
if (id === resolvedVirtualReactRefreshId) {
|
||||
return reactRefreshPreamble;
|
||||
}
|
||||
if (id === '\0noop') {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
"@types/react-dom": "^18.2.6",
|
||||
"@vitejs/plugin-react": "^4.0.3",
|
||||
"typescript": "^5.1.6",
|
||||
"wxt": "^0.5.0"
|
||||
"wxt": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"devDependencies": {
|
||||
"typescript": "^5.1.6",
|
||||
"vite-plugin-solid": "^2.7.0",
|
||||
"wxt": "^0.5.0"
|
||||
"wxt": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"svelte-check": "^3.4.6",
|
||||
"tslib": "^2.6.0",
|
||||
"typescript": "^5.1.6",
|
||||
"wxt": "^0.5.0"
|
||||
"wxt": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
|
||||
</a>
|
||||
</div>
|
||||
<h1>WXT 2 + Svelte</h1>
|
||||
<h1>WXT + Svelte</h1>
|
||||
|
||||
<div class="card">
|
||||
<Counter />
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.1.6",
|
||||
"wxt": "^0.5.0"
|
||||
"wxt": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"typescript": "^5.1.6",
|
||||
"vue-tsc": "^1.8.4",
|
||||
"wxt": "^0.5.0"
|
||||
"wxt": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user