The goal is to create an npm module with React components and functions that can be imported in a NextJS project. The problem is that the JS is bundled in one file instead of maintaining the src/
folder structure, and when the module is imported the functions are not working (undefined).
The folder structure is like this:
- src
index.ts
- components
testComponent.module.css
testComponent.tsx
testReturn.ts
The src/index.ts
exports everything from components/
. In the module I have these files:
tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"target": "ESNext",
"module": "CommonJS",
"outDir": "dist",
"sourceMap": true,
"strict": true,
"declaration": true,
"esModuleInterop": true,
"noEmit": false,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"moduleResolution": "node",
"plugins": [{ "name": "typescript-plugin-css-modules" }],
"baseUrl": "./src"
},
"include": ["src/**/*"]
}
webpack.config.js
const path = require("path");
module.exports = {
mode: process.env.NODE_ENV || "development",
entry: {
index: "./src/index.ts",
},
output: {
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
loader: "ts-loader",
options: {
configFile: "tsconfig.json",
},
},
{
test: /\.css$/i,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[name]__[local]__[hash:base64:5]",
},
},
},
],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
}
In package.json I have these settings:
{
"name": "testmodule",
"scripts": {
"prebuild": "rimraf dist",
"build": "webpack"
},
"main": "dist/index.js",
"files": [
"dist"
],
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.22",
"@types/react-dom": "^18.2.7",
"@types/css-modules": "^1.0.3",
"ts-loader": "^9.4.4",
"typescript": "^5.2.2",
"webpack-cli": "^5.1.4",
"rimraf": "^5.0.4",
"css-loader": "^6.8.1",
"style-loader": "^3.3.3",
"typescript-plugin-css-modules": "^5.0.1",
"webpack": "^5.88.2"
}
}
Now I seem to have 2 issues:
dist/index.js
while I want it to maintain the src/
folder structure. The folder structure exists, but only d.ts
files are in there.yarn link
to locally link the library) the functions do import without errors in VS Code but in the dev server (a clean NextJS setup) they give an error that they are undefined.Can anyone shed some light on this? Maybe Rollup is more suited for this?
After hours of trying to get Webpack do the job I found out that rollup just did it with just some small configuration:
import commonjs from "@rollup/plugin-commonjs";
import nodeResolve from "@rollup/plugin-node-resolve";
import postcss from "rollup-plugin-postcss";
import tsConfigPaths from "rollup-plugin-tsconfig-paths";
import typescript from "rollup-plugin-typescript2";
import pkg from "./package.json";
const config = [
{
input: "src/index.ts",
output: {
preserveModules: true,
preserveModulesRoot: "src",
dir: "./dist",
format: "es",
},
external: [...Object.keys(pkg.dependencies || {}), "react/jsx-runtime"],
plugins: [
tsConfigPaths(),
nodeResolve({ extensions: [".tsx", ".ts", ".jsx", ".js", ".json"] }),
typescript({
typescript: require("typescript"),
}),
commonjs(),
postcss(),
],
},
];
export default config;
Maybe Webpack is up to it to, but this worked for me.