Vue3 upgrade - ERROR: [plugin: vite:dep-scan] Cannot read properties of undefined (reading 'length') - vue.js

I migrated from webpack to vite successfully in a vue2 project and now I am upgrading from vue2 to vue3.
I made it until step 4 in this guide: https://v3-migration.vuejs.org/migration-build.html#installation, and now the build process gives me this error.
ERROR: [plugin: vite:dep-scan] Cannot read properties of undefined (reading 'length')
It looks like the vite compat builder is not able to find the file /src/main.js, because if I rename or even delete the file, the error remains the same.
Did I miss something?
✘ [ERROR] [plugin vite:dep-scan] Cannot read properties of undefined (reading 'length')
node_modules/vite/dist/node/chunks/dep-59dc6e00.js:60384:34:
60384 │ if (importee.length < pattern.length) {
╵ ^
at matches (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:60384:35)
at /home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:60443:58
at Array.find (<anonymous>)
at Context.resolveId (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:60443:42)
at Object.resolveId (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:38837:55)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async resolve (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:39049:26)
at async /home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:39257:34
at async callback (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/esbuild/lib/main.js:929:28)
at async handleRequest (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/esbuild/lib/main.js:709:30)
This error came from the "onResolve" callback registered here:
node_modules/vite/dist/node/chunks/dep-59dc6e00.js:39253:18:
39253 │ build.onResolve({
╵ ~~~~~~~~~
at setup (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:39253:19)
at handlePlugins (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/esbuild/lib/main.js:851:23)
at Object.buildOrServe (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/esbuild/lib/main.js:1145:7)
at /home/user/projects/ipfs-search/dweb-search-frontend/node_modules/esbuild/lib/main.js:2087:17
at new Promise (<anonymous>)
at Object.build (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/esbuild/lib/main.js:2086:14)
at Object.build (/home/user/projects/ipfs-search/dweb-search-frontend/node_modules/esbuild/lib/main.js:1935:51)
at /home/user/projects/ipfs-search/dweb-search-frontend/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:38997:54
at Array.map (<anonymous>)
The plugin "vite:dep-scan" was triggered by this import
html:/home/user/projects/ipfs-search/dweb-search-frontend/index.html:1:7:
1 │ import "/src/main.js"
╵ ~~~~~~~~~~~~~~
Build failed with 1 error:
node_modules/vite/dist/node/chunks/dep-59dc6e00.js:60384:34: ERROR: [plugin: vite:dep-scan] Cannot read properties of undefined (reading 'length')
vite.config.js:
import { defineConfig } from 'vite';
import path from 'path';
import createVuePlugin from '#vitejs/plugin-vue';
export default defineConfig({
plugins: [
createVuePlugin({
template: {
compilerOptions: {
compatConfig: {
MODE: 2,
},
},
},
}),
],
server: {
port: 8080,
},
resolve: {
alias: [
{
vue: '#vue/compat',
},
{
find: '#',
replacement: path.resolve(__dirname, 'src'),
},
],
},
});

Well I found an answer; the alias in vite.config.js:
{
vue: '#vue/compat',
},
seemed to cause the error.
Note that this snippet was copied directly from the official vue.js vue3 migration guide. After I removed it, the error disappeared, and more comprehensible errors came, as the ones I expected.

Inspired by Frido Emans answer, I found the issue was using a list into alias. I ended up replacing
export default defineConfig({
plugins: [vue()],
resolve: {
alias: [
{
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
{
find: "./runtimeConfig",
replacement: "./runtimeConfig.browser",
},
]
},
});
by (notice the alias list is gone)
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"./runtimeConfig": "./runtimeConfig.browser",
"#": fileURLToPath(new URL("./src", import.meta.url))
}
},
});

Related

Internal server error: Cannot read property 'length' of undefined

Getting an error
[vite] Internal server error: Cannot read property 'length' of undefined
This is happening while trying to run my vue project using vite.
Below is the error stack:
Build failed with 1 error: node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:59574:34: ERROR: [plugin: vite:dep-scan] Cannot read property 'length' of undefined 2:44:29 PM [vite] Internal server error: Cannot read property 'length' of undefined at matches (/Users/pandocorp/Desktop/pando/codes/pando-app/frontend/shipper/node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:59574:35) at /Users/pandocorp/Desktop/pando/codes/pando-app/frontend/shipper/node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:59633:58 at Array.find () at Context.resolveId (/Users/pandocorp/Desktop/pando/codes/pando-app/frontend/shipper/node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:59633:42) at Object.resolveId (/Users/pandocorp/Desktop/pando/codes/pando-app/frontend/shipper/node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:36609:55) at processTicksAndRejections (internal/process/task_queues.js:95:5) at async ModuleGraph.resolveUrl (/Users/pandocorp/Desktop/pando/codes/pando-app/frontend/shipper/node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:56244:26) at async ModuleGraph.getModuleByUrl (/Users/pandocorp/Desktop/pando/codes/pando-app/frontend/shipper/node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:56124:23) at async doTransform (/Users/pandocorp/Desktop/pando/codes/pando-app/frontend/shipper/node_modules/vite/dist/node/chunks/dep-27bc1ab8.js:55582:20)
My vite.config.js
import { defineConfig } from 'vite';
import { createVuePlugin } from 'vite-plugin-vue2';
const config = require('./config');
const path = require('path');
export default defineConfig({
plugins: [createVuePlugin()],
server: {
port: 8080,
},
resolve: {
alias: [
{
'#': path.resolve(__dirname, './src'),
},
{
'#common': path.resolve(__dirname, '../common-v2'),
},
// {
// find: path.resolve(__dirname, '../static'),
// replacement: config.dev.assetsSubDirectory,
// ignore: ['.'],
// },
// {
// find: path.resolve(__dirname, '../firebase-messaging-sw.js'),
// replacement: 'firebase-messaging-sw.js',
// ignore: ['.'],
// },
],
},
build: {
chunkSizeWarningLimit: 600,
cssCodeSplit: false,
},
});
When I encountered this error, adding the following to vite.config.js seemed to resolve it.
resolve: {
alias: [
{
find: /^~(.*)$/,
replacement: 'node_modules/$1',
},
],
},
I had the same issue with a brand new Vite project. I don't know if this is your case, but I created this new project under a directory of another project like so:
/some/path/my-project <- "parent project"
/some/path/my-project/... <- other project files
/some/path/my-project/node_modules
/some/path/my-project/... <- other project files
/some/path/my-project/brand-new-vite-project <--- THIS ONE!
This nesting seems to generate the issue, because I moved the brand new project elsewhere and everything worked as expected.
Same problem encountered while getting throug Amplify "getting started" (which requires a new alias)
The solution for me was to rewrite the config as follows
export default defineConfig({
plugins: [vue()],
resolve: {
alias: [
{
"./runtimeConfig": "./runtimeConfig.browser",
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
],
},
});

can't import the named export 'computed' from non ecmascript module pinia and Vue 2

After installing Pinia on my Vue 2 project, and imported it in the main.js file
I got this error
Failed to compile.
./node_modules/pinia/dist/pinia.mjs 1147:44-52
Can't import the named export 'computed' from non EcmaScript module (only default export is available)
This Vue configuration should do the trick
// vue.config.js
module.exports = {
configureWebpack: {
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto"
}
]
}
}
}
As mentioned in this Github issue.

ESM library generated with rollup-plugin-postcss throws Cannot find module '../node_modules/style-inject/dist/style-inject.es.js'

We are maintaining an internal library which is exporting ESM modules using Rollup. We have just recently switched to using CSS modules, which we have set with rollup-plugin-postcss. We want to inject these styles into the head rather than have an external file.
Our built bundle generates the ESM file with:
import styleInject from '../node_modules/style-inject/dist/style-inject.es.js';
Our consuming library then fails with
Uncaught Error: Cannot find module '../node_modules/style-inject/dist/style-inject.es.js'
I would expect the ESM export to import styleInject from 'style-inject' and style-inject to be included in the package-lock.json as a dependency. What is the correct way of using CSS Modules and injecting into the head for the consumer of a library?
rollup.config.js
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import babel from '#rollup/plugin-babel';
import json from '#rollup/plugin-json';
import postcss from 'rollup-plugin-postcss';
import pkg from './package.json';
import fg from 'fast-glob';
import path from 'path';
export default [
{
input: 'src/index.js',
external: external(),
output: [
{
name: '#my/packageName',
file: pkg.module,
format: 'es',
sourcemap: true,
},
],
plugins: [
{
name: 'watch-external',
async buildStart() {
const files = await fg(['src/index.d.ts', 'playground/**/*']);
for (let file of files) {
this.addWatchFile(path.resolve(file));
}
},
},
json(),
postcss({
modules: true,
}),
babel({
exclude: /node_modules/,
babelHelpers: 'runtime',
babelrc: false,
presets: [
[
'#babel/preset-env',
{
modules: false,
useBuiltIns: 'entry',
corejs: 3,
targets: {
ie: 11,
},
},
],
'#babel/preset-react',
],
plugins: [
'#babel/plugin-transform-runtime',
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-export-namespace-from',
],
}),
commonjs(),
],
},
];
function external() {
const { dependencies = {}, peerDependencies = {} } = pkg;
const externals = [
...Object.keys(dependencies),
...Object.keys(peerDependencies),
];
return id =>
// match 'lodash' and 'lodash/fp/isEqual' for example
externals.some(dep => id === dep || id.startsWith(`${dep}/`));
}
There is a bug in the library where the import is relative rather than being the module name.
There is an open pr, but the library looks like it is no longer being maintained. There are two recommended solutions in the comments:
String replace the built output
Add a custom rollup plugin to do this
This is not a bug at all. It works properly because stylesInject is just a function from 'styles-inject' package, so we can allow it to be bundled. But it is not bundled because most likely you have this setting in your rollup.config.js:
external: [
/node_modules/
]
So, replace it with a code bellow and it will work:
external: (id) => {
if (/style-inject/.test(id)) return false;
if (/node_modules/.test(id)) return true;
return false;
},
also, you can write a regexp for it instead
You need to do 2 things:
Add style-inject dependency in package.json
"dependencies": {
"style-inject": "^0.3.0"
},
Add following plugin to rollup.config.js
const plugins = [
...
{
/**
* - https://github.com/egoist/rollup-plugin-postcss/issues/381#issuecomment-880771065
* - https://lightrun.com/answers/egoist-rollup-plugin-postcss-esm-library-generated-with-rollup-plugin-postcss-throws-cannot-find-module-node_modulesstyle-in
*/
name: 'Custom Rollup Plugin`',
generateBundle: (options, bundle) => {
Object.entries(bundle).forEach((entry) => {
// early return if the file we're currently looking at doesn't need to be acted upon by this plugin
if (!entry[0].match(/.*(.scss.js)$/)) {
return;
}
// this line only runs for .scss.js files, which were generated by the postcss plugin.
// depending on the use-case, the relative path to style-inject might need to change
bundle[entry[0]].code = entry[1].code.replace(
/\.\.?\/[^\n"?:*<>|]+\/style-inject\/dist\/style-inject.es.js/g,
'style-inject',
);
});
},
}
];
References:
https://github.com/egoist/rollup-plugin-postcss/issues/381#issuecomment-880771065
https://lightrun.com/answers/egoist-rollup-plugin-postcss-esm-library-generated-with-rollup-plugin-postcss-throws-cannot-find-module-node_modulesstyle-in

How to deal with the problem of TS2367 error after the replacement code?

I use rollup-replace as the variable switch of the builder in the project, but I have encountered a problem when using it with TypeScript, and I always give me errors like this:
semantic error TS2367: This condition will always return'true' since the types'boolean' and'string' have no overlap.
I will write code like this in my code
// a.ts
import Prod from './prod';
import Pre from './pre';
If(process.env.PROD === ’true’){
console.log(‘is prod’);
Prod.init();
} else {
console.log(‘is pre’);
Pre.init();
}
// rollup.config.js
import typescript from 'rollup-plugin-typescript2';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import replace from '#rollup/plugin-replace';
export default [
{
input: 'src/a.ts',
output: { file: 'dist/a.js', format: 'iife' },
plugins: [
replace({ values: { 'process.env.PROD': JSON.stringify(true) }, preventAssignment: true }),
resolve({ browser: true }),
commonjs(),
typescript(),
]
}
]
In the above build code, replace needs to precede resolve, because it is necessary to use replace to avoid useless JS from being imported into the bundle file.
Who can help me solve this meaningless error message?
In the rollup document, I found the advanced usage of treeshake.moduleSideEffects, which talked about the ability I want to achieve.
import typescript from 'rollup-plugin-typescript2';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import replace from '#rollup/plugin-replace';
export default [
{
input: 'src/a.ts',
output: { file: 'dist/a.js', format: 'iife' },
plugins: [
replace({ values: { 'process.env.PROD': JSON.stringify(true) }, preventAssignment: true }),
resolve({ browser: true }),
commonjs(),
typescript(),
],
treeshake: {
moduleSideEffects: false, // Prune unused pure external imports
},
}
]

How would I import a module within an npm package subfolder with webpack?

Lets say theres a package in node_modules called foo and I want to import a module within a library such as foo/module via webpack & babel...
import Foo from 'foo'; works
import SomeOtherModule from 'foo/module'; fails with the following:
Module not found: Error: Cannot resolve module 'foo/module' in
/Users/x/Desktop/someproject/js
Which makes make it seem like webpack is looking for the file in the wrong place instead of node_modules
My webpack.config looks like this:
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: ['babel-polyfill','./js/script.js'],
output: {
path: __dirname,
filename: './build/script.js'
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
cacheDirectory: true,
presets: ['es2015']
}
}
],
},
plugins: [
new webpack.NoErrorsPlugin()
],
stats: {
colors: true
},
devtool: 'source-map'
};
It should work with import 'foo/module';. It will resolve file ./node_modules/foo/module.js or ./node_modules/foo/module/index.js and not something like ./node_modules/foo/node_modules/module/index.js if it expected (in that case you better to install module via npm).
You can define a custom path using the module attribute in your package.json. Example:
{
...
"module": "dist/mylib.min.js",
...
}
See What is the "module" package.json field for?