Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confusing buildStart behavior with createServer API #19607

Open
7 tasks done
hi-ogawa opened this issue Mar 8, 2025 · 3 comments · May be fixed by #19624
Open
7 tasks done

Confusing buildStart behavior with createServer API #19607

hi-ogawa opened this issue Mar 8, 2025 · 3 comments · May be fixed by #19624

Comments

@hi-ogawa
Copy link
Collaborator

hi-ogawa commented Mar 8, 2025

Describe the bug

Vite-node has been using a following style of programmatic server setup https://github.com/vitest-dev/vitest/blob/94b27af595b5029b6201a7bcf2702169fe7ae6a4/packages/vite-node/src/cli.ts#L86-L99, but I'm not sure whether buildStart should be manually triggered on Vite 6 (also how perEnvironmentStartEndDuringDev should be enabled on server level or plugin level).

const server = await createServer({});
await server.pluginContainer.buildStart({})

One issue with manually calling buildStart is that:

// repro1.js
const server = await createServer({
    configFile: false,
    plugins: [
      {
        name: 'repro',
        async buildStart() {
          console.log('[repro:buildStart:in]');
          await new Promise((r) => setTimeout(r, 500));
          console.log('[repro:buildStart:out]');
        },
        transform(_code, id) {
          console.log('[repro:transform]', id);
        },
      },
    ]
});
await server.pluginContainer.buildStart({})
await server.ssrLoadModule("./src/empty.js");

which causes transform to happen before buildStart finishes:

$ node repro1.js 
[repro:buildStart:in]
[repro:transform] /xxx/src/empty.js
[repro:buildStart:out]

Probably this was the cause of vitest-dev/vitest#7479 and this can potentially break vite:client-inject since its transform relies on buildStart

return defineReplacer(injectConfigValues(code))

On the other hand, one issue with not manually calling buildStart is that this breaks css import like in #19606.

// repro2.js
  const server = await createServer({
    configFile: false,
  });
  await server.ssrLoadModule("./src/import-css.js");
$ node repro2.js 
12:16:38 PM [vite] (ssr) Error when evaluating SSR module ./src/import-css.js: Cannot read properties of undefined (reading 'get')
  Plugin: vite:css-post
  File: /home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/src/style.css
      at TransformPluginContext.transform (file:///home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-glQox-ep.js:48442:50)
      at EnvironmentPluginContainer.transform (file:///home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-glQox-ep.js:47637:19)
      at async loadAndTransform (file:///home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-glQox-ep.js:41320:27)
node:internal/process/promises:394
    triggerUncaughtException(err, true /* fromPromise */);
    ^

Error [TypeError]: Cannot read properties of undefined (reading 'get')
    at TransformPluginContext.transform (file:///home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-glQox-ep.js:48442:50)
    at EnvironmentPluginContainer.transform (file:///home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-glQox-ep.js:47637:19)
    at async loadAndTransform (file:///home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-glQox-ep.js:41320:27) {
  plugin: 'vite:css-post',
  id: '/home/hiroshi/code/personal/reproductions/vite-19598-ssr-only-css/src/style.css',
  pluginCode: '.test {\n  color: orange\n}\n',
  runnerError: Error: RunnerError

Reproduction

https://stackblitz.com/github/hi-ogawa/reproductions/tree/main/vite-19598-ssr-only-css?file=repro1.js

Steps to reproduce

  • open stackblitz
  • run node repro1.js
  • run node repro2.js

System Info

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.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    vite: ^6.2.0 => 6.2.1

Used Package Manager

npm

Logs

No response

Validations

@sapphi-red
Copy link
Member

I'm not sure whether buildStart should be manually triggered on Vite 6 (also how perEnvironmentStartEndDuringDev should be enabled on server level or plugin level).

buildStart is called automatically for the client env for the other environments it's not called. This is to keep the compat with older versions.

// For backward compatibility, buildStart and watchChange are called only for the client environment
// buildStart is called per environment for a plugin with the perEnvironmentStartEndDuring dev flag

I think we need to keep this compat for now.

One issue with manually calling buildStart is that:
...
which causes transform to happen before buildStart finishes:

I think that's because we're missing await / return here.

async buildStart(_options?: InputOptions): Promise<void> {
;(this.environments.client as DevEnvironment).pluginContainer.buildStart(
_options,
)
}
async watchChange(
id: string,
change: { event: 'create' | 'update' | 'delete' },
): Promise<void> {
;(this.environments.client as DevEnvironment).pluginContainer.watchChange(
id,
change,
)
}

I think we can fix this way instead.

@rChaoz
Copy link

rChaoz commented Mar 11, 2025

Not sure exactly why yet, but my scripts (that I run using vite-node) all started failing recently with this error:

TypeError: injectConfigValues is not a function
    at TransformPluginContext.transform
[at](plugin: 'vite:client-inject')

        return defineReplacer(injectConfigValues(code));
                              ^

so, it seems like it would be fixed by the PR above. I haven't figured out exactly what change caused this error to start appearing, but it seems to be a dependency update.

@hi-ogawa
Copy link
Collaborator Author

@rChaoz This one is supposed to be fixed (worked around) on vite-node side vitest-dev/vitest#7480. Do you have latest vite-node 3.0.8?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants