vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
67.86k stars 6.11k forks source link

Dynamically inserted importmap doesn't work in development mode #15192

Open sorin-davidoi opened 10 months ago

sorin-davidoi commented 10 months ago

Describe the bug

Inserting an importmap at runtime via a script statement in head does not work in development mode because the script that is inserting it is placed after the module import of @vite/client. This results in the following error:

An import map is added after module script load was triggered.

This issue only affects the development mode because it it caused by the presence of the @vite/client import.

Related issues:

Workaround: trick Vite into thinking that the script that is inserting the importmap is an importmap itself - this will make sure that it gets sorted before the module import of @vite/client. This can be achieved by adding an attribute to it that matches this regular expression (e.g. data-vite-workaround="type=importmap").

Reproduction

https://stackblitz.com/edit/vitejs-vite-yde4az?file=index.html

Steps to reproduce

Run npm install && npm run dev.

Expected result:

Actual result:

Note that running npm install && npm run build && npm run preview works as expected.

System Info

Output from running the command in the linked StackBlitz:

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.18.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 9.4.2 - /usr/local/bin/npm
    pnpm: 8.10.5 - /usr/local/bin/pnpm
  npmPackages:
    vite: ^5.0.2 => 5.0.4

Used Package Manager

npm

Logs

No response

Validations

stackblitz[bot] commented 10 months ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

HexaField commented 7 months ago

@sorin-davidoi Would you be able to provide some more information about how to work around this?

kfrederix commented 3 months ago

I faced the same issue. Worked around it now by combining a build with watch mode + preview to simulate "dev" mode instead of using the "normal" vite dev-server.

One way I can think of, to solve this, would be to add a new option in the vite config file to disable the insertion of the @vite/client script. When someone would disable it, they still have the freedom to manually load the @vite/client from javascript in case they want to have the auto-reload / hmr functionality during dev mode. E.g. they could add something like this in their code (after the importmap has been added):

if (import.meta.env.MODE === 'development') {
  const origin = new URL(import.meta.url).origin;
  import(/* @vite-ignore */ `${origin}/@vite/client`);
}
vageez commented 2 months ago

I had a similar issue, trying to inject a script to dynamically generate my import map.

I have been able to solve this using the api plugin transformindexhtml.

https://vitejs.dev/guide/api-plugin#transformindexhtml

Example.

const htmlPlugin = () => {
    return {
        name: 'html-transform',
        transformIndexHtml(html) {
            const newHtml = html.replace(
                /<script type="module" src="\/@vite\/client"><\/script>/,
                `<script src="./importmap.js"></script><script type="module" src="/@vite/client"></script>`,
            )
            return newHtml
        },
    }
}

const developmentConfig = () => ({
        server: {
            hmr: true
        },
        plugins: [
            htmlPlugin()
        ]
});