aklinker1 / vite-plugin-web-extension

Vite plugin for developing Chrome/Web Extensions
https://vite-plugin-web-extension.aklinker1.io/
MIT License
654 stars 57 forks source link

React Fast Refresh is broken #84

Closed vimcaw closed 1 year ago

vimcaw commented 1 year ago

Summary

I created a simple project from pnpm create vite-plugin-web-extension, and chose react-ts template, and the popup page doesn't work, after right-clicking to inspect the popup, the console shows an error:

Popup.tsx:3 Uncaught Error: React refresh preamble was not loaded. Something is wrong.
    at Popup.tsx:3:33

In Popup.tsx:3:33:

if (!window.$RefreshReg$)
    throw new Error("React refresh preamble was not loaded. Something is wrong.");

That mean window.$RefreshReg$ is missing.

CleanShot 2023-03-12 at 16 30 03@2x CleanShot 2023-03-12 at 16 31 26@2x

When I open http://localhost:5173/src/popup.html directly in the browser, anything works well.

After diving deep, I found their HTML file has some differences: In dist/src/popup.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://localhost:5173/src/popup.css">
    <title>Popup</title>
  <script src="http://localhost:5173/@vite/client" type="module"></script>  <script type="module" crossorigin src="/src/popup.js"></script>
</head>

  <body></body>

  <script type="module" src="http://localhost:5173/src/pages/Popup.tsx"></script>
</html>

In http://localhost:5173/src/popup.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module">import { injectIntoGlobalHook } from "/@react-refresh";
injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;</script>

    <script type="module" src="/@vite/client"></script>

    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./popup.css" />
    <title>Popup</title>
  </head>

  <body></body>

  <script type="module" src="./pages/Popup.tsx"></script>
</html>

Obviously, this part is missing:

<script type="module">import { injectIntoGlobalHook } from "/@react-refresh";
injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;</script>

That's why it not working in the browser extension.

Reproduction

https://github.com/vimcaw/vite-plugin-web-extension-bug-reproduction

Environment

  System:
    OS: macOS 13.2.1
    CPU: (8) arm64 Apple M1
    Memory: 61.09 MB / 8.00 GB
    Shell: 3.5.0 - /usr/local/bin/fish
  Binaries:
    Node: 19.7.0 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 9.5.0 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 111.0.5563.64
    Safari: 16.3
  npmPackages:
    vite: ^4.1.4 => 4.1.4 
    vite-plugin-web-extension: ^3.0.0 => 3.0.0
aklinker1 commented 1 year ago

Good catch. I think I know how to solve this. Rather than transforming HTML file myself, I should fetch it from the dev server. That way all plugins apply properly.

The main problem with that is that the dev server starts after we transform the HTML files.... I'll have to figure out a way to change up the order. Hmmm...

Thanks for sharing, I'll try and get this fixed today

vimcaw commented 1 year ago

I try to inject the missing script to dist/src/popup.html as a temp workaround, but chrome throws some errors:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval' http://localhost:* http://127.0.0.1:*". Either the 'unsafe-inline' keyword, a hash ('sha256-ziklEcVoMM12lYuZURXft0fBUfwBk0XufOImFQWUAXk='), or a nonce ('nonce-...') is required to enable inline execution.
CleanShot 2023-03-12 at 22 29 58@2x

Seems like an inline script is disallowed in a browser extension, maybe it only allows a script file link, which will make it tricky to solve (maybe place this to a separate file and link it).

aklinker1 commented 1 year ago

Yeah, the problem is this content is only included when using the react plugin, and I don't want to make any react-only changes to the codebase if I don't need to.

I can add unsafe-inline to the CSV for dev mode. If that doesn't work, I can process the HTML after the server has returned it and put inline scripts in their own virtual module.

aklinker1 commented 1 year ago

Yup, Chrome is not OK with us using unsafe-inline. I'll have to take the virtual module approach... Which will be a bit harder.

aklinker1 commented 1 year ago

Alright, I got something working. I didn't have to deal with the inline script nonsense, Vite took care of it automatically for me.

I am getting two warnings. I don't have much experience working with Vite and React, so I'll debug later today.

Good progress though, this should be fixed soon.

https://user-images.githubusercontent.com/10101283/224556843-8fbe6f2d-c1c1-4320-8b89-90c903dc2ea4.mov

aklinker1 commented 1 year ago

Nevermind, one last change before I get off. I fixed the top warning.

The bottom warning appears to be a problem with calling ReactDOM.createRoot inside the file that I'm saving to HMR. I need to separate it from the component. I'll update the template with a better file layout.

So this is pretty much good to go. #85 will be merged later today soon and I'll get a release out.

aklinker1 commented 1 year ago

Fixed in #85, and updated templates in #88.

Fix released in v3.0.1.

vimcaw commented 1 year ago

After testing, seems like still has an error here, I think in HTML file, import "/@react-refresh" should be import "http://localhost:5173/@react-refresh" (see https://github.com/vitejs/vite/issues/1984#issuecomment-778420441)

CleanShot 2023-03-16 at 09 50 27

vite-plugin-web-extension-bug-reproduction on  main [!] via  v19.7.0 took 8s
❯ pnpm dev

> test@1.0.0 dev /Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction
> vite dev

Build Steps
  1. Building src/popup.html indvidually
  2. Building src/background.ts indvidually

Building src/popup.html (1/2)

  VITE v4.1.4  ready in 566 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help
vite v4.1.4 building for production...
✓ 3 modules transformed.
[vite]: Rollup failed to resolve import "/@react-refresh" from "/Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/src/popup.html?html-proxy&index=0.js".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
file:///Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/node_modules/.pnpm/vite@4.1.4/node_modules/vite/dist/node/chunks/dep-ca21228b.js:44792
            throw new Error(`[vite]: Rollup failed to resolve import "${exporter}" from "${id}".\n` +
                  ^

Error: [vite]: Rollup failed to resolve import "/@react-refresh" from "/Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/src/popup.html?html-proxy&index=0.js".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
    at onRollupWarning (file:///Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/node_modules/.pnpm/vite@4.1.4/node_modules/vite/dist/node/chunks/dep-ca21228b.js:44792:19)
    at onwarn (file:///Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/node_modules/.pnpm/vite@4.1.4/node_modules/vite/dist/node/chunks/dep-ca21228b.js:44562:13)
    at Object.onwarn (file:///Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/node_modules/.pnpm/rollup@3.19.1/node_modules/rollup/dist/es/shared/node-entry.js:25097:13)
    at ModuleLoader.handleInvalidResolvedId (file:///Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/node_modules/.pnpm/rollup@3.19.1/node_modules/rollup/dist/es/shared/node-entry.js:23779:26)
    at file:///Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/node_modules/.pnpm/rollup@3.19.1/node_modules/rollup/dist/es/shared/node-entry.js:23739:26 {
  watchFiles: [
    '/Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/src/popup.html',
    '\x00vite/modulepreload-polyfill',
    '/Users/vimcaw/Downloads/vite-plugin-web-extension-bug-reproduction/src/popup.html?html-proxy&index=0.js'
  ]
}

Node.js v19.7.0
 ELIFECYCLE  Command failed with exit code 1.
aklinker1 commented 1 year ago

@vimcaw Oh sorry, I ran into that error when looking into this and fixed it as well. I forgot to mention there is a change you have to make on your side as well:

https://github.com/aklinker1/vite-plugin-web-extension/blob/e80d47f034e3cd05071ca4da4962b0e93db1c5da/packages/create-vite-plugin-web-extension/templates/react-ts/vite.config.ts#L25-L32

This change is already in both the templates.

vimcaw commented 1 year ago

After adding it, anything works well, thanks!