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

Virtual modules break esbuild dependency scanning during SSR building #2047

Closed
3 tasks done
airhorns opened this issue Feb 16, 2021 · 3 comments
Closed
3 tasks done

Comments

@airhorns
Copy link
Contributor

  • Read the docs.
  • Use Vite >=2.0. (1.x is no longer supported)
  • If the issue is related to 1.x -> 2.0 upgrade, read the Migration Guide first.

Describe the bug

When passing custom entrypoints to vite, if the entrypoint doesn't exist on the filesystem directly, the build throws an error when trying to scan the dependencies of the entrypoint when building with ssr: true. This can occur when using virtual modules (like vite-react-pages might), or when using /@fs/ entrypoints to be explicit about absolute paths in the entrypoints. In dev server mode, these entrypoints work fine. I think this would not be common to just modules provided by @rollup-plugin/virtual, but any module who's contents were provided or changed by a rollup plugin.

Reproduction

Here's a reproduction using a branch of the vite playgrounds as an example: main...airhorns:virtual-entrypoint-bug

I believe the issue occurs because the esbuild based dependency scanner doesn't realize that the module is provided by a rollup plugin, and so it looks for it in the filesystem.

Here's a debug log of the build:

inspector ~/C/v/p/p/ssr-react (virtual-entrypoint-bug*) ➜  env DEBUG="*" npm run build:server

> test-ssr-react@0.0.0 build:server
> vite build --ssr --outDir dist/server

  vite:config cjs config loaded in 26ms +0ms
  vite:config using resolved config: {
  vite:config   plugins: [
  vite:config     'alias',
  vite:config     'react-refresh',
  vite:config     'vite:dynamic-import-polyfill',
  vite:config     'vite:resolve',
  vite:config     'vite:html',
  vite:config     'vite:css',
  vite:config     'vite:esbuild',
  vite:config     'vite:json',
  vite:config     'vite:wasm',
  vite:config     'vite:worker',
  vite:config     'vite:asset',
  vite:config     'virtual',
  vite:config     'vite:define',
  vite:config     'vite:css-post',
  vite:config     'vite:build-html',
  vite:config     'commonjs',
  vite:config     'vite:data-uri',
  vite:config     'rollup-plugin-dynamic-import-variables',
  vite:config     'vite:import-analysis',
  vite:config     'vite:esbuild-transpile',
  vite:config     'vite:reporter'
  vite:config   ],
  vite:config   esbuild: { jsxInject: "import React from 'react';" },
  vite:config   build: {
  vite:config     target: [ 'es2019', 'edge16', 'firefox60', 'chrome61', 'safari11' ],
  vite:config     polyfillDynamicImport: true,
  vite:config     outDir: 'dist/server',
  vite:config     assetsDir: 'assets',
  vite:config     assetsInlineLimit: 4096,
  vite:config     cssCodeSplit: true,
  vite:config     sourcemap: true,
  vite:config     rollupOptions: { input: [Object] },
  vite:config     commonjsOptions: { include: [Array], extensions: [Array] },
  vite:config     minify: false,
  vite:config     terserOptions: {},
  vite:config     cleanCssOptions: {},
  vite:config     write: true,
  vite:config     emptyOutDir: null,
  vite:config     manifest: false,
  vite:config     lib: false,
  vite:config     ssr: true,
  vite:config     ssrManifest: false,
  vite:config     brotliSize: true,
  vite:config     chunkSizeWarningLimit: 500
  vite:config   },
  vite:config   configFile: '/Users/airhorns/Code/vite/packages/playground/ssr-react/vite.config.js',
  vite:config   inlineConfig: {
  vite:config     root: undefined,
  vite:config     base: undefined,
  vite:config     mode: undefined,
  vite:config     configFile: undefined,
  vite:config     logLevel: undefined,
  vite:config     clearScreen: undefined,
  vite:config     build: { ssr: true, outDir: 'dist/server' }
  vite:config   },
  vite:config   root: '/Users/airhorns/Code/vite/packages/playground/ssr-react',
  vite:config   base: '/',
  vite:config   resolve: { dedupe: undefined, alias: [ [Object] ] },
  vite:config   publicDir: '/Users/airhorns/Code/vite/packages/playground/ssr-react/public',
  vite:config   command: 'build',
  vite:config   mode: 'production',
  vite:config   isProduction: true,
  vite:config   optimizeCacheDir: '/Users/airhorns/Code/vite/packages/playground/ssr-react/node_modules/.vite',
  vite:config   server: {},
  vite:config   https: undefined,
  vite:config   env: { BASE_URL: '/', MODE: 'production', DEV: false, PROD: true },
  vite:config   assetsInclude: [Function: assetsInclude],
  vite:config   logger: {
  vite:config     hasWarned: false,
  vite:config     info: [Function: info],
  vite:config     warn: [Function: warn],
  vite:config     error: [Function: error],
  vite:config     clearScreen: [Function: clearScreen]
  vite:config   },
  vite:config   createResolver: [Function: createResolver]
  vite:config } +4ms
building SSR bundle for production...
  vite:deps Crawling dependencies using entries:
  vite:deps   /Users/airhorns/Code/vite/packages/playground/ssr-react/src/entry-about.jsx
  vite:deps   /Users/airhorns/Code/vite/packages/playground/ssr-react/src/entry-home.jsx
  vite:deps   /Users/airhorns/Code/vite/packages/playground/ssr-react/my-cool-module.tsx +0ms
  vite:resolve 0ms   /Users/airhorns/Code/vite/packages/playground/ssr-react/my-cool-module.tsx -> null +0ms
 > error: [vite:dep-scan] ENOENT: no such file or directory, open '/Users/airhorns/Code/vite/packages/playground/ssr-react/my-cool-module.tsx'

  vite:resolve 2ms   react -> /Users/airhorns/Code/vite/node_modules/react/index.js +18ms
error during build:
Error: Build failed with 1 error:
error: [vite:dep-scan] ENOENT: no such file or directory, open '/Users/airhorns/Code/vite/packages/playground/ssr-react/my-cool-module.tsx'
    at failureErrorWithLog (/Users/airhorns/Code/vite/node_modules/esbuild/lib/main.js:1145:15)
    at buildResponseToResult (/Users/airhorns/Code/vite/node_modules/esbuild/lib/main.js:896:32)
    at /Users/airhorns/Code/vite/node_modules/esbuild/lib/main.js:991:20
    at /Users/airhorns/Code/vite/node_modules/esbuild/lib/main.js:550:9
    at handleIncomingPacket (/Users/airhorns/Code/vite/node_modules/esbuild/lib/main.js:639:9)
    at Socket.readFromStdout (/Users/airhorns/Code/vite/node_modules/esbuild/lib/main.js:517:7)
    at Socket.emit (node:events:379:20)
    at addChunk (node:internal/streams/readable:313:12)
    at readableAddChunk (node:internal/streams/readable:288:9)
    at Socket.Readable.push (node:internal/streams/readable:227:10)

System Info

  • vite version: 2a6109a
  • Operating System: Darwin inspector 20.2.0 Darwin Kernel Version 20.2.0: Wed Dec 2 20:39:59 PST 2020; root:xnu-7195.60.75~1/RELEASE_X86_64 x86_64
  • Node version: v15.7.0
  • Package manager (npm/yarn/pnpm) and version: yarn 1.22.10

Logs (Optional if provided reproduction)

  1. Run vite or vite build with the --debug flag.
  2. Provide the error log here.
@yyx990803
Copy link
Member

This only happens because you are using a virtual module as entry. What is the use case for that?

@airhorns
Copy link
Contributor Author

I'm trying to build something like vite-react-pages (or next/nuxt for that matter) that gets handed a list of entrypoints from one system and needs to wrap each entrypoint in a harness to run a ReactDOM.hydrate call and add some other components like the router and a <Layout/> component. It works fine in the dev server because rollup can just do its thing.

The reason I am not doing the one-true-entrypoint-approach that then does routing inside it, or uses import.meta.glob is that I want to use a router outside the assets system to govern which entrypoint gets rendered. For React SSR it's also a bit easier to do many entrypoints like this that synchronously import the top level component they are wrapping and then dynamically import all the others, instead of having one true entrypoint that dynamically imports all the components and then have the server side renderer have to figure out how to suspend while the dynamic imports get loaded up. I would also prefer to not use inlineDynamicImports because then I can't have multiple entrypoints at all (rollup doesn't support that), which I would like so that I get shared chunks between totally different parts of my app that are using different routers all together.

I think this is kind of a symptom of an architectural issue though, which is that the esbuild dep scanner doesn't know about rollup's modules. If this is the first time this has cropped up then maybe I am just out to lunch, but if vite really wants to support the rollup plugin API, then I imagine virtual modules aren't the only thing that use the load plugin hook to do weird things.

@airhorns
Copy link
Contributor Author

Thank you sir!

@github-actions github-actions bot locked and limited conversation to collaborators Jul 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants