Error migrating library from rollup to vitejs - reactjs

Problem
I have a project let's call it root (based on Preact) that relies on a components package (based on React):
Building it using rollup works fine. When I switch components to use vitejs to build, root fails at runtime with this error:
index.es.js? [sm]:770 Uncaught TypeError: Cannot read properties of undefined (reading 'current')
at jsxDEV (index.es.js? [sm]:770:64)
at jsxWithValidation (index.es.js? [sm]:954:17)
at jsxWithValidationDynamic (index.es.js? [sm]:992:13)
at d.RecipesExplorer [as constructor] (index.es.js? [sm]:1915:33)
at d.O [as render] (index.js:532:14)
at j (index.js:190:14)
at w (children.js:137:3)
at L (index.js:418:4)
at j (index.js:246:20)
at w (children.js:137:3)
I'm not changing anything in root or how it's run. It's built using vitejs as well (in both scenarios).
Rollup config
Here's the rollup.config.js for components (this is the build scenario that works without issue):
// rollup.config.js for components
import { defineConfig } from 'rollup'
import typescript from 'rollup-plugin-typescript2'
import json from '#rollup/plugin-json'
import styles from 'rollup-plugin-styles'
export default defineConfig([
{
input: 'src/index.ts',
output: [
// I don't think we need both of these. Keeping them since we had them for now in webpack
{
dir: 'dist/esm',
format: 'es',
},
{
dir: 'dist/cjs',
format: 'cjs',
},
],
plugins: [typescript({}), json()],
external: ['react', 'react-dom', 'styled-components'],
}
])
Vitejs config
When I switch to using vitejs, this is the vite config:
// vite.config.js for components
import { defineConfig } from 'vite'
import react from '#vitejs/plugin-react'
import { resolve } from 'path'
export default defineConfig({
mode: 'development',
server: {
port: 3000,
open: false,
},
plugins: [react()],
build: {
minify: false,
target: 'modules',
outDir: './dist',
rollupOptions: {
external: ['react', 'react-dom', 'styled-components'],
},
lib: {
entry: resolve(__dirname, './src/index.ts'),
formats: ['cjs', 'es'],
fileName: format => `index.${format}.js`,
},
emptyOutDir: true,
},
})
Package.json snippet
Since vitejs and rollup place files in different directories, I change package.json as well.
For vitejs:
// package.json when configured for vitejs
"name": "components",
...
"exports": {
".": {
"import": "./dist/index.es.js",
"require": "./dist/index.cjs.js"
}
},
"scripts": {
"build": "vite build",
"build:rollup": "rollup -c",
},
...
For rollup:
// package.json when configured for rollup
"name": "components",
...
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
}
},
"scripts": {
"build": "vite build",
"build:rollup": "rollup -c",
},
...
Command I'm running & conclusion
When I build components using npm run build (with vite), I get the above error. When I build with npm run build:rollup I get no error.
What am I doing wrong?
Appendix: Root config and package.json
My vitejs config file for root in case that's helpful. Root uses preact and components are built in React.
// vite.config.js for root
import { defineConfig } from 'vite';
import preact from '#preact/preset-vite';
import { resolve } from 'path';
const config = {
RecipeExplorer: {
entry: resolve(__dirname, './src/recipe-explorer.ts'),
fileName: 'recipe-explorer',
},
RecipeList: {
entry: resolve(__dirname, './src/recipe-list.ts'),
fileName: 'recipe-list',
},
RecipeDetailsLegacy: {
entry: resolve(__dirname, './src/recipe-details.ts'),
fileName: 'recipe-details',
},
};
/** IMPORTANT:
* We're using this LIB_NAME env variable so we can create multiple input and output files at build time.
* At the moment this is a work around. Issue is here: https://github.com/vitejs/vite/issues/4530
* Once the above issue gets resolved, we can do away with this workaround.
*/
const currentConfig = config[process.env.LIB_NAME];
if (currentConfig === undefined) {
console.warn(
'LIB_NAME is not defined or is not valid. If you are running a build command LIB_NAME must be specified.',
);
}
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
react: 'preact/compat',
'react-dom': 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react/jsx-runtime': 'preact/jsx-runtime',
},
},
plugins: [preact()],
server: {
port: 3010,
host: '0.0.0.0',
},
build: {
outDir: './dist',
lib: {
...currentConfig,
formats: ['cjs', 'es'],
},
emptyOutDir: false,
},
});
I run root using npm run dev which is defined as vite:
// package.json for root
"name": "root",
"scripts": {
"lint": "eslint 'src/**/*.{ts,tsx}'",
"test": "jest",
"dev": "vite",
...
}
...

Related

Vitest config doesn't detect jsdom environment

I'm in a Vite/React/TypeScript application and I'm configuring my first test with Vitest.
When I run my Button test (yarn vitest), I get this error:
packages/frontend/src/components/Generic/Button/Button.test.tsx > Button > should render the button
ReferenceError: document is not defined
I understand that Vitest does not work with JSDom. I have tried several things:
KO: Specifying in the vite.config.ts file to use JSDom
OK: Adding a vitest.config.ts file specifying to use JSDom
OK: Adding an annotation (#vitest-environment jsdom) at the top of the test file
I would prefere use the first option (use vite.config.ts) to share only one configuration. Is it possible ?
Note 1 : JSdom i already installed has "devDependencies".
Note 2 : to use vitest.config.ts i should update the script in package.json like that :
"test": "vitest --config ./packages/frontend/vitest.config.ts"
Here are my files:
// vite.config.ts
import { defineConfig } from 'vite'
import react from '#vitejs/plugin-react'
import viteTsConfigPaths from 'vite-tsconfig-paths'
import tailwindcss from 'tailwindcss'
export default defineConfig({
server: {
port: 4200,
host: 'localhost',
},
rollupOption: {
external: ['#internals/components/index']
},
define: {
global: {},
},
plugins: [
react(),
tailwindcss(),
viteTsConfigPaths({
root: '../../',
}),
],
resolve: {
alias: {
// runtimeConfig is a special alias that is used to import the correct config file
'./runtimeConfig': './runtimeConfig.browser',
// public alias
'#publics': `${__dirname}/public`,
// only internals (private) aliases are allowed here
'#internals/components': `${__dirname}/src/components`,
'#internals/features': `${__dirname}/src/features`,
'#internals/hooks': `${__dirname}/src/hooks`,
'#internals/models': `${__dirname}/src/models`,
'#internals/utils': `${__dirname}/src/utils`,
'#internals/types': `${__dirname}/src/types`,
'#internals/styles': `${__dirname}/src/styles`,
'#internals/assets': `${__dirname}/src/assets`,
'#internals/store': `${__dirname}/src/store`,
'#internals/config': `${__dirname}/src/config`,
'#internals/services': `${__dirname}/src/services`,
},
},
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['*.tsx', '*.ts', '*.jsx', '*.js'],
},
})
I tried to add a like this vitest.config.ts :
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
include: ['*.ts', '*.tsx'], // FIXME
environment: 'jsdom',
},
})

WalletConnect fails to get bundled with vite

I have a vite project that uses #walletconnect/client. Everything works fine with
npm run dev
but during build (npm run build) I get these errors
error during build:
Error: 'removeHexPrefix' is not exported by node_modules/#walletconnect/encoding/dist/cjs/index.js, imported by node_modules/#walletconnect/utils/dist/esm/ethereum.js
I have tried a few vite configurations from github
1.
optimizeDeps: {
include: ['#walletconnect/*']
},
optimizeDeps: {
exclude: ['#walletconnect/*']
},
3
build: {
commonjsOptions: {exclude: ['#walletconnect*'], include: []},
},
I do not know anything else to do, but if you have come across this issue or something similar. Please let me know how you solved yours.
Thank you.
Had the same issue (I highly suggest you to check it out). Fixed with this config:
import { defineConfig } from "vite";
import { svelte } from "#sveltejs/vite-plugin-svelte";
import { NodeGlobalsPolyfillPlugin } from "#esbuild-plugins/node-globals-polyfill";
import inject from "#rollup/plugin-inject";
import nodePolyfills from "rollup-plugin-polyfill-node";
// https://vitejs.dev/config/
export default defineConfig({
base: "./",
// Node.js global to browser globalThis
define: {
global: "globalThis",
},
plugins: [
svelte(),
inject({
util: "util/",
}),
],
build: {
rollupOptions: {
plugins: [nodePolyfills()],
},
commonjsOptions: {
transformMixedEsModules: true,
},
},
optimizeDeps: {
esbuildOptions: {
// Node.js global to browser globalThis
define: {
global: "globalThis",
},
// Enable esbuild polyfill plugins
plugins: [
NodeGlobalsPolyfillPlugin({
buffer: true,
}),
],same issue
},
},
});```

How to setup alias for Jest with craco

I'm building react app provided by create-react-app.
I use craco to make configuration simplify and have set up alise for TypeScript and Webpack.
But when I run test command, the following error is displayed.
Error Message
spec/showMessage.test.tsx
● Test suite failed to run
Cannot find module '#/components/atom/TextButton' from 'src/pages/index.tsx'
Require stack:
src/pages/index.tsx
spec/showMessage.test.tsx
3 | import styled from 'styled-components';
4 |
> 5 | import { TextButton } from '#/components/atom/TextButton';
| ^
This is my craco.config.js
craco.config.js
const path = require("path");
module.exports = {
jest: {
configure: {
roots: ['<rootDir>/src', '<rootDir>/spec'],
testMatch: ['<rootDir>/spec/**/*.{spec,test}.{js,jsx,ts,tsx}'],
},
},
webpack: {
alias: {
"#": path.resolve(__dirname, "./src/"),
"##": path.resolve(__dirname, "./")
},
extensions: ['.ts', '.tsx'],
},
};
I found the solution, I updated package.json like below, it solves this problem.
{
"name": "xxxxx",
:
},
"jest": {
"moduleNameMapper": {
"^#/(.+)": "<rootDir>/src/$1"
}
}
}

ReactJS: Importing symlinked components error: Module parse failed: Unexpected token: You may need an appropriate loader to handle this file type

I'm writing a React component library which I want to use in other projects without much overhead ( bit, create-react-library, generact, etc. ) and without publishing. I want to use npm install ../shared_lib to add it to my project as a symlink in /node_modules. This command adds the symlink to project node_modules. In my shared_lib I just have a test to export default a <div></div>:
import React from 'react';
const TryTest = function() {
return (
<div>
TryTest
</div>
)
}
export default TryTest;
The problem I'm facing is the following error when I import the component into my working project:
import TryTest from 'shared_lib';
Error:
ERROR in ../shared_lib/src/index.js 6:4
Module parse failed: Unexpected token (6:4)
You may need an appropriate loader to handle this file type.
| const TryTest = function() {
| return (
> <div>
| TryTest
| </div>
# ./src/App.js 27:0-33 28:12-19
# ./src/index.js
# multi babel-polyfill ./src/index.js
If I import anything from shared_lib other than a file with jsx - for example, a string or a function, etc. - it works fine.
EDIT: the application webpack has resolve object's symlinks prop set to false:
resolve: {
symlinks: false
},
EDIT: After applying the solution in the answer below (https://stackoverflow.com/a/60980492/3006493), I later changed symlinks prop back to true. I didn't need to set it to false for the solution to work and render shared_lib components.
My app's loader:
{
test: /\.jsx?$/,
include: [
path.join( __dirname, 'src'), // app/src
fs.realpathSync(__dirname + '/node_modules/shared_lib'), // app/node_modules/shared_lib/dist/shared_lib.js
],
exclude: /node_modules/,
use: [ 'babel-loader' ]
}
EDIT: When I applied the solution in the answer below, the loader now looks like this:
{
test: /\.jsx?$/,
include: [
path.join( __dirname, 'src'), // app/src
fs.realpathSync(__dirname + '/node_modules/shared_lib'), // app/node_modules/shared_lib/dist/shared_lib.js
],
exclude: /node_modules/,
use: [ {
loader: 'babel-loader',
options: require("./package.json").babel
}
]
}
App's current .babelrc settings (I also tried removing .babelrc and including the presets in package.json with same result):
{
"presets": [ "#babel/preset-react", "#babel/preset-env"]
}
**EDIT: After applying the solution in the answer below, I ended up putting babel presets back into package.json.
"babel": {
"presets": [
"#babel/preset-react",
"#babel/preset-env"
]
},
I researched for a while to find a solution to this and apparently webpack has issues bundling symlinked react components? I am not using create-react-app.
So, I tried to bundle the shared_lib before importing it into the project, just to see what would happen. Here's the final webpack config (I tried other configurations as well):
const pkg = require('./package.json');
const path = require('path');
const buildPath = path.join( __dirname, 'dist' );
const clientPath = path.join( __dirname, 'src');
const depsPath = path.join( __dirname, 'node_modules');
const libraryName = pkg.name;
module.exports = [
'cheap-module-source-map'
].map( devtool => ({
bail: true,
mode: 'development',
entry: {
lib : [ 'babel-polyfill', path.join( clientPath, 'index.js' ) ]
},
output: {
path: buildPath,
filename: 'shared_lib.js',
libraryTarget: 'umd',
publicPath: '/dist/',
library: libraryName,
umdNamedDefine: true
},
// to avoid bundling react
externals: {
'react': {
commonjs: 'react',
commonjs2: 'react',
amd: 'React',
root: 'React'
}
},
module: {
rules: [
{
test: /\.jsx?$/,
include: [
clientPath
],
exclude: /node_modules/,
use: [ 'babel-loader' ],
},
]
},
devtool,
optimization: {
splitChunks: {
chunks: 'all',
},
}
}));
And the package.json for the shared_lib
{
"name": "shared_lib",
"version": "1.0.0",
"description": "",
"main": "dist/shared_lib.js",
"scripts": {
"clean": "rm -rf dist/",
"build": "$(npm bin)/webpack --config ./webpack.config.js",
"prepublish": "npm run clean && npm run build"
},
"author": "",
"license": "ISC",
"peerDependencies": {
"react": "^16.8.6"
},
"devDependencies": {
"react": "^16.8.6",
"#babel/core": "^7.9.0",
"#babel/preset-env": "^7.9.0",
"#babel/preset-react": "^7.9.4",
"babel-loader": "^8.1.0",
"babel-polyfill": "^6.26.0",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
},
"babel": {
"presets": [
"#babel/preset-react",
"#babel/preset-env"
]
}
}
The package is bundled without errors:
When I try to import the component in the same way:
import TryTest from 'shared_lib';
The console.log returns undefined.
The path to the library file in my app is fine, because if I erase everything in shared_lib/dist/shared_lib.js and just write export default 1 the console.log(TryTest) in my App.js will return 1.
I tried changing libraryTarget property in shared_lib/webpack.config to libraryTarget: 'commonjs'. The result of console.log(TryTest) becomes {shared_lib: undefined}.
Has anyone ever run into this?
I found what finally worked for me and rendered the symlinked shared_lib to the app.
This answer: https://github.com/webpack/webpack/issues/1643#issuecomment-552767686
Worked well rendering symlinked shared_lib components. I haven't discovered any drawbacks from using this solution, but it's the only one that worked so far.

Error: Cannot export when target is not server. with next js and zeit-NOW during deployee

I am working a react app where i am using next js and express, I have choose zeit now for servless but when i deploying this facing error Error: No serverless pages were built
next.config.js
const configuration = withTypescript(
withLess({,
target: process.env.NODE_ENV === "development" ? "server" : "serverless",
cssModules: true,
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables // make your antd custom effective
},
exportPathMap: async function(defaultPathMap) {
return {
"/": { page: "/index" },
};
},
webpack: config => {
config.plugins = config.plugins || [];
config.plugins = [
...config.plugins,
// Read the .env file
new Dotenv({
path: path.join(__dirname, "../.env"),
systemvars: true
})
];
return config;
},
})
);
module.exports = configuration;
using next version : "#types/next": "^8.0.0",
now.json
{
"version": 2,
"name": "web",
"builds": [
{ "src": "package.json", "use": "#now/next" }
],
}
inside package json
"scripts": {
"dev": "next src",
"build": "next build src",
"start": "next run build && next start src",
"export": "npm run build && next export src -o ./out",
"now-build": "next build src","
},
Getting error from zeit Now logs
preparing lambda files...
2019-04-19T17:24:04.955Z Error: No serverless pages were built. https://err.sh/zeit/now-builders/now-next-no-serverless-pages-built
at Object.exports.build (/tmp/utils/build-module/node_modules/#now/next/index.js:305:13)
at <anonymous>
please help me here to figure it out.
Thanks.

Resources