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

Cannot import local PNPM Workspace CommonJS package #11657

Open
7 tasks done
Mathdrquinn opened this issue Jan 10, 2023 · 7 comments
Open
7 tasks done

Cannot import local PNPM Workspace CommonJS package #11657

Mathdrquinn opened this issue Jan 10, 2023 · 7 comments
Labels
contribution welcome documentation Improvements or additions to documentation

Comments

@Mathdrquinn
Copy link

Mathdrquinn commented Jan 10, 2023

Describe the bug

Running vite build on a pnpm workspace application cannot prebundle and identify local package definitions/

$ vite build

"formatFullName" is not exported by "../../packages/util/lib/index.js", imported by "src/pages/MyAccountPage.vue".
 9: const _hoisted_1 = { key: 1 };
10: const _hoisted_2 = { key: 2 };
11: import { formatFullName } from "@local-package/util";
             ^
error during build:
RollupError: "formatFullName" is not exported by "../../packages/util/lib/index.js", imported by "src/pages/MyAccountPage.vue".

Repo structure

├─ apps
│  └─ app1
          └─ vite.config.ts
└─ packages
   └─ util

app1/vite.config.js

import AutoImport from 'unplugin-auto-import/vite';
import AutoImportComponents from 'unplugin-vue-components/vite';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    tsconfigPaths(),
    vue(),
    AutoImport({
      presetOverriding: true,
      imports: 'vue',
    }),
    AutoImportComponents({
      dirs: ['src/components'],
    }),
  ],
  server: {
    port: 5000,
    // Docs: https://vitejs.dev/config/server-options.html#server-hmr
    watch: {
      ignored: ['!**/node_modules/@local-package/**'],
    },
  },
  optimizeDeps: {
    include: [
      '@local-package/util',
      'axios',
    ],
  },
  build: {
    commonjsOptions: {
      include: [
        /lib-cjs/,
        /node_modules/,
        /@local-package\/util/],
    },
    outDir: 'out',
  },
});

app1/package.json

{
  "name": "app1",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "....": "...",
    "@local-package/util": "workspace:^1.0.1",
    "vite": "^4.0.4"
  },
  "devDependencies": {
     "....": "..."
  }
}

util/package.json

{
  "name": "@local-package/util",
  "version": "1.0.1",
  "description": "",
  "type": "commonjs",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "files": [
    "lib/**/*"
  ],
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prebuild": "rm -rf lib",
    "build": "tsc",
    "prepare": "pnpm build"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Version: "vite": ^4.0.4"

Reproduction

https://stackblitz.com/edit/vitejs-vite-3mgrsj?file=apps/app1/vite.config.js

Steps to reproduce

  1. pnpm install
  2. pnpm --filter app1 build

System Info

System:
    OS: macOS 12.1
    CPU: (8) arm64 Apple M1
    Memory: 102.59 MB / 8.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 18.12.1 - ~/.nvm/versions/node/v18.12.1/bin/node
    npm: 8.19.2 - ~/.nvm/versions/node/v18.12.1/bin/npm
  Browsers:
    Chrome: 108.0.5359.124
    Firefox: 105.0.3
    Safari: 15.2

Used Package Manager

pnpm

Logs

❯ npx vite build --debug
  vite:config bundled config file loaded in 120.80ms +0ms
  vite:esbuild init tsconfck (root: /home/projects/vitejs-vite-3mgrsj) +0ms
  vite:esbuild init tsconfck (root: /home/projects/vitejs-vite-3mgrsj) +0ms
  vite:esbuild init tsconfck (root: /home/projects/vitejs-vite-3mgrsj) +1ms
  vite:esbuild init tsconfck (root: /home/projects/vitejs-vite-3mgrsj) +0ms
  vite:esbuild init tsconfck end +2ms
  vite:esbuild init tsconfck end +0ms
  vite:esbuild init tsconfck end +0ms
  vite:esbuild init tsconfck end +0ms
  vite:config using resolved config: {
  vite:config   optimizeDeps: {
  vite:config     disabled: 'build',
  vite:config     include: [ '@local-package/util' ],
  vite:config     esbuildOptions: { preserveSymlinks: false }
  vite:config   },
  vite:config   build: {
  vite:config     target: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ],
  vite:config     cssTarget: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ],
  vite:config     outDir: 'dist',
  vite:config     assetsDir: 'assets',
  vite:config     assetsInlineLimit: 4096,
  vite:config     cssCodeSplit: true,
  vite:config     sourcemap: false,
  vite:config     rollupOptions: {},
  vite:config     minify: 'esbuild',
  vite:config     terserOptions: {},
  vite:config     write: true,
  vite:config     emptyOutDir: null,
  vite:config     copyPublicDir: true,
  vite:config     manifest: false,
  vite:config     lib: false,
  vite:config     ssr: false,
  vite:config     ssrManifest: false,
  vite:config     reportCompressedSize: true,
  vite:config     chunkSizeWarningLimit: 500,
  vite:config     watch: null,
  vite:config     commonjsOptions: { include: [Array], extensions: [Array] },
  vite:config     dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] },
  vite:config     modulePreload: { polyfill: true }
  vite:config   },
  vite:config   configFile: '/home/projects/vitejs-vite-3mgrsj/apps/app1/vite.config.js',
  vite:config   configFileDependencies: [ '/home/projects/vitejs-vite-3mgrsj/apps/app1/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     optimizeDeps: { force: undefined },
  vite:config     build: {}
  vite:config   },
  vite:config   root: '/home/projects/vitejs-vite-3mgrsj/apps/app1',
  vite:config   base: '/',
  vite:config   rawBase: '/',
  vite:config   resolve: {
  vite:config     mainFields: [ 'module', 'jsnext:main', 'jsnext' ],
  vite:config     browserField: true,
  vite:config     conditions: [],
  vite:config     extensions: [
  vite:config       '.mjs',  '.js',
  vite:config       '.mts',  '.ts',
  vite:config       '.jsx',  '.tsx',
  vite:config       '.json'
  vite:config     ],
  vite:config     dedupe: [],
  vite:config     preserveSymlinks: false,
  vite:config     alias: [ [Object], [Object] ]
  vite:config   },
  vite:config   publicDir: '/home/projects/vitejs-vite-3mgrsj/apps/app1/public',
  vite:config   cacheDir: '/home/projects/vitejs-vite-3mgrsj/apps/app1/node_modules/.vite',
  vite:config   command: 'build',
  vite:config   mode: 'production',
  vite:config   ssr: {
  vite:config     format: 'esm',
  vite:config     target: 'node',
  vite:config     optimizeDeps: { disabled: true, esbuildOptions: [Object] }
  vite:config   },
  vite:config   isWorker: false,
  vite:config   mainConfig: null,
  vite:config   isProduction: true,
  vite:config   plugins: [
  vite:config     'vite:build-metadata',
  vite:config     'vite:pre-alias',
  vite:config     'alias',
  vite:config     'vite:modulepreload-polyfill',
  vite:config     'vite:resolve',
  vite:config     'vite:html-inline-proxy',
  vite:config     'vite:css',
  vite:config     'vite:esbuild',
  vite:config     'vite:json',
  vite:config     'vite:wasm-helper',
  vite:config     'vite:worker',
  vite:config     'vite:asset',
  vite:config     'vite:wasm-fallback',
  vite:config     'vite:define',
  vite:config     'vite:css-post',
  vite:config     'vite:build-html',
  vite:config     'vite:worker-import-meta-url',
  vite:config     'vite:asset-import-meta-url',
  vite:config     'vite:force-systemjs-wrap-complete',
  vite:config     'vite:watch-package-data',
  vite:config     'commonjs',
  vite:config     'vite:data-uri',
  vite:config     'vite:dynamic-import-vars',
  vite:config     'vite:import-glob',
  vite:config     'vite:build-import-analysis',
  vite:config     'vite:esbuild-transpile',
  vite:config     'vite:terser',
  vite:config     'vite:reporter',
  vite:config     'vite:load-fallback'
  vite:config   ],
  vite:config   server: {
  vite:config     preTransformRequests: true,
  vite:config     middlewareMode: false,
  vite:config     fs: { strict: true, allow: [Array], deny: [Array] }
  vite:config   },
  vite:config   preview: {
  vite:config     port: undefined,
  vite:config     strictPort: undefined,
  vite:config     host: undefined,
  vite:config     https: undefined,
  vite:config     open: undefined,
  vite:config     proxy: undefined,
  vite:config     cors: undefined,
  vite:config     headers: undefined
  vite:config   },
  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     warnOnce: [Function: warnOnce],
  vite:config     error: [Function: error],
  vite:config     clearScreen: [Function: clearScreen],
  vite:config     hasErrorLogged: [Function: hasErrorLogged]
  vite:config   },
  vite:config   packageCache: Map(0) { set: [Function (anonymous)] },
  vite:config   createResolver: [Function: createResolver],
  vite:config   worker: {
  vite:config     format: 'iife',
  vite:config     plugins: [
  vite:config       'vite:build-metadata',
  vite:config       'vite:pre-alias',
  vite:config       'alias',
  vite:config       'vite:modulepreload-polyfill',
  vite:config       'vite:resolve',
  vite:config       'vite:html-inline-proxy',
  vite:config       'vite:css',
  vite:config       'vite:esbuild',
  vite:config       'vite:json',
  vite:config       'vite:wasm-helper',
  vite:config       'vite:worker',
  vite:config       'vite:asset',
  vite:config       'vite:wasm-fallback',
  vite:config       'vite:define',
  vite:config       'vite:css-post',
  vite:config       'vite:build-html',
  vite:config       'vite:worker-import-meta-url',
  vite:config       'vite:asset-import-meta-url',
  vite:config       'vite:force-systemjs-wrap-complete',
  vite:config       'vite:watch-package-data',
  vite:config       'commonjs',
  vite:config       'vite:data-uri',
  vite:config       'vite:dynamic-import-vars',
  vite:config       'vite:import-glob',
  vite:config       'vite:build-import-analysis',
  vite:config       'vite:esbuild-transpile',
  vite:config       'vite:terser',
  vite:config       'vite:load-fallback'
  vite:config     ],
  vite:config     rollupOptions: {},
  vite:config     getSortedPlugins: [Function: getSortedPlugins],
  vite:config     getSortedPluginHooks: [Function: getSortedPluginHooks]
  vite:config   },
  vite:config   appType: 'spa',
  vite:config   experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false },
  vite:config   getSortedPlugins: [Function: getSortedPlugins],
  vite:config   getSortedPluginHooks: [Function: getSortedPluginHooks]
  vite:config } +7ms
vite v4.0.4 building for production...
✓ 7 modules transformed.
"formatName" is not exported by "../../packages/util/lib/index.js", imported by "counter.js".
file: /home/projects/vitejs-vite-3mgrsj/apps/app1/counter.js:1:9
1: import { formatName } from '@local-package/util';
            ^
2: 
3: export function setupCounter(element) {
error during build:
RollupError: "formatName" is not exported by "../../packages/util/lib/index.js", imported by "counter.js".
    at error (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:1992:30)
    at Module.error (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:12987:16)
    at Module.traceVariable (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:13370:29)
    at ModuleScope.findVariable (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:11851:39)
    at FunctionScope.findVariable (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:6712:38)
    at ChildScope.findVariable (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:6712:38)
    at ReturnValueScope.findVariable (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:6712:38)
    at ChildScope.findVariable (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:6712:38)
    at Identifier.bind (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:7807:40)
    at CallExpression.bind (file://file:///home/projects/vitejs-vite-3mgrsj/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:5604:23)

~/projects/vitejs-vite-3mgrsj/apps/app1 1s
❯ 

Validations

@jameschensmith
Copy link

TL;DR, adding resolve: { preserveSymlinks: true } to your Vite configuration appears to resolve the issue.

I've gone down a giant rabbit hole on this issue. This has to do with preserveSymlinks (which finds its history in the --preserve-symlinks Node.js flag). No, it's not build.rollupOptions.preserveSymlinks even though the error states RollupError, but rather resolve.preserveSymlinks which must override this option for Rollup & the other build tools (see esbuild#preserve-symlinks). Perhaps that could be clarified in the documentation.

Apparently, Node.js doesn't have a very good history with symlinking (see nodejs/node#10107), and so that's what we're dealing with here, I believe. I wish this flag wasn't needed, because apparently there are some nasty side-effects. I'm pretty sure it only happens with CJS, as I originally set up a repro, and when I was using ESM, the symlink seemed to resolve correctly.

Hope this helps. I feel your pain. I ran into this with a simple npm workspace project.

@Mathdrquinn
Copy link
Author

@jameschensmith Thank you for the swell reply. I'll give it a try and report back.

@Mathdrquinn
Copy link
Author

That does appear to solve my conundrum @jameschensmith . I appreciate you taking the time to give a thoughtful response.

For those finding this later on, I've updated my sandbox app to demonstrate the solution: https://stackblitz.com/edit/vitejs-vite-3mgrsj?file=apps%2Fapp1%2Fvite.config.js

@lsdsjy
Copy link
Contributor

lsdsjy commented Mar 1, 2023

Another solution is to use https://pnpm.io/package_json#dependenciesmetainjected, see: https://stackblitz.com/edit/vitejs-vite-nzqcwp?file=apps/app1/package.json

@vsviridov
Copy link

vsviridov commented Mar 19, 2023

@lsdsjy Your solution helped in my case. preserveSymlinks made a bunch of other packages error out...
However with this change I have to completely nuke node_modules for vite to pick up changes in the shared package.

@bluwy
Copy link
Member

bluwy commented Apr 27, 2023

In @rollup/plugin-commonjs, there's this docs:

So include and exclude paths should handle real paths rather than symlinked paths (e.g. ../common/node_modules/** instead of node_modules/**).:

So commonjsOptions.include should be configured with /packages\/util/ instead of /@local-package\/util/. I think we can improve this in our docs.

@marcus-sa
Copy link

Another solution is to use https://pnpm.io/package_json#dependenciesmetainjected, see: https://stackblitz.com/edit/vitejs-vite-nzqcwp?file=apps/app1/package.json

That did the trick for me, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution welcome documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

6 participants