Module not founds: Can't resolve 'fs' from dependency packaged with rollup - javascript

my rollup config:
import babel from 'rollup-plugin-babel';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
const extensions = ['.js', '.jsx'];
export default {
input: 'src/index.js',
output: [
{
dir: 'lib/cjs',
format: 'cjs',
},
{
dir: 'lib/esm',
format: 'esm',
},
],
external: ['fs'], //i've tried with and without this
plugins: [
babel({
extensions,
exclude: 'node_modules/**',
}),
resolve(),
commonjs(),
],
};
and I bundle up a package that uses import fs from 'fs';
When I pack it as 'my-dep' and try to use it in another project as a dependency, using the cjs
const myDep = require("my-dep")
works but using esm
import myDep from 'my-dep'
throws an error
Module not found: Error: Cannot resolve module 'fs' in <path-to-my-project>/my-dep/lib/cjs

Related

Including a specific module in rollup build

I'm using Rollup to build a UMD version of my module.
This rollup.config.js successfully builds my module, without including #tensorflow/tfjs:
import path from 'path';
import commonjs from '#rollup/plugin-commonjs';
import { nodeResolve } from '#rollup/plugin-node-resolve';
export default {
input: "dist/tmp/index.js",
output: {
file: "dist/umd/index.js",
format: 'umd',
name: 'Foo',
globals: {
'#tensorflow/tfjs': 'tf',
}
},
context: 'window',
external: ['#tensorflow/tfjs'],
}
However, I rely on a second module (tensor-as-base64) that I do want to include in the bundle. I cannot figure out how to include that specific module.
From a lot of googling it seems like I need to use #rollup/plugin-commonjs and #rollup/plugin-node-resolve, but I can't find any examples for how to scope the includes to a specific folder under node_modules. I've tried something like this:
import commonjs from '#rollup/plugin-commonjs';
import { nodeResolve } from '#rollup/plugin-node-resolve';
export default {
input: "dist/tmp/index.js",
output: {
file: "dist/umd/index.js",
format: 'umd',
name: 'Foo',
globals: {
'#tensorflow/tfjs': 'tf',
}
},
context: 'window',
external: ['#tensorflow/tfjs'],
plugins: [
nodeResolve({
}),
commonjs({
include: [/tensor-as-base64/],
namedExports: {
'tensor-as-base64': ['tensorAsBase64'],
},
}),
]
};
This seems to just hang with no output.
Any tips on how to include a single specific module from the node_modules folder (and ignore everything else in that folder)?
Update 1
I tried this config:
export default {
input: "dist/tmp/index.js",
output: {
file: "dist/umd/index.js",
format: 'umd',
name: 'Foo',
globals: {
'#tensorflow/tfjs': 'tf',
}
},
context: 'window',
external: ['#tensorflow/tfjs'],
plugins: [
nodeResolve({
resolveOnly: [
/^(?!.*(#tensorflow\/tfjs))/,
],
}),
],
})
This produces the following output:
dist/tmp/index.js → dist/umd/index.js...
[!] Error: 'default' is not exported by ../../node_modules/tensor-as-base64/dist/index.js, imported by dist/tmp/upscale.js
Which is accurate in that tensor-as-base64 does not export default.
After including the commonjs plugin, it gets into an infinite loop. I think that's where I'm missing some bit of configuration.
I should add that this is a monorepo, so maybe there's an issue with node_modules being at the root of the folder?

How to propperly build react modular library

I'm trying to create a react components library which is based on Typescript and SASS. The components library will be used in multiple other typescript projects, so type exports are needed as well. Ideally I want to mimic something like "Material-UI"/"React-Bootrap" libraries dist output solutions.
Example project structure:
|Tabs
+--Tabs.tsx
+--Tabs.scss
+--index.tsx
index.tsx
index.tsx
export { Tabs } from './Tabs/Tabs';
Tabs/index.tsx
import React from 'react';
import './Tabs.scss';
interface TabsProps {
...
}
export const Tabs: React.FC<TabsProps> = (props) => <div>...</div>
Tabs/index.tsx
export { Tabs } from './Tabs';
Expected built dist structure should mimic the src structure:
|Tabs
+--Tabs.js
+--Tabs.d.ts
+--index.js
+--index.d.ts
index.js
index.tsx
I tried analyzing open source projects and see how they are building the libraries, however I could not find libraries using the same approaches that I could reuse.
The solutions I've tried:
Webpack: While I could compile typescript and sass files the webpack would always emit only one file specified in the output section, which usually would be bundled and I would loose the ability to import single component from a specific component's module. I know I can specify multiple entry points, but the project will be having a lot of exports and manually specifying them is not an option...
Example config I tried:
const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
// sass-loader is not used here yet, but should be once desired structure can be reached
{
test: /\.tsx?$/,
loader: 'babel-loader',
},
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ test: /\.js$/, loader: "source-map-loader" }
]
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
extensions: [".tsx", ".ts", ".js"],
plugins: [
new TsconfigPathsPlugin({ configFile: "./tsconfig.build.json" })
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
};
Rollup: Similar situation as webpack
Example config that I tried:
// rollup.config.js
import babel from 'rollup-plugin-babel';
import sass from 'rollup-plugin-sass';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import react from 'react';
import reactDom from 'react-dom';
const babelOptions = {
exclude: /node_modules/,
// We are using #babel/plugin-transform-runtime
runtimeHelpers: true,
extensions: ['.js', '.ts', '.tsx'],
configFile: './babel.config.js',
};
const nodeOptions = {
extensions: ['.js', '.tsx', '.ts'],
};
const commonjsOptions = {
ignoreGlobal: true,
include: /node_modules/,
namedExports: {
react: Object.keys(react),
'react-dom': Object.keys(reactDom)
},
};
export default {
input: 'src/index.tsx',
output: {
name: '[name].js',
dir: 'dist',
format: 'umd',
sourcemap: true,
},
plugins: [
nodeResolve(nodeOptions),
sass(),
commonjs(commonjsOptions),
babel(babelOptions)
],
};
Babel: I managed to compile the typescript code however once I came close to transpiling SASS files I would end up with suggestions to use webpack for that...
TSC: I successfully could run the typescript compiler and it would compile all the files without problems and would maintain the same structure. However TSC does not support other transpiling options so after a lot of searches I would end up with suggestions to use webpack and "ts-loader" or "babel-loader"..
tsconfig:
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"lib": [ "es2015", "dom" ],
"outDir": "dist",
"baseUrl": ".",
"declaration": true,
"composite": true,
"module": "commonjs",
"target": "es5"
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}
Desirced solution:
I should be able after compiling the library and installing it in another project be able to run the following:
import { Tabs } from 'my-lib/Tabs';
import { Tabs } from 'my-lib';
After a lot of playing around I managed to produce the wanted result with rollup. The only downside of the current configuration is that it does not support newly added files in the --watch mode. The magic setting is under the output.preserveModules
Config:
// rollup.config.js
import commonjs from '#rollup/plugin-commonjs';
import typescript from '#rollup/plugin-typescript';
import postcss from 'rollup-plugin-postcss';
import postcssUrl from 'postcss-url';
import resolve from "#rollup/plugin-node-resolve";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
export default {
input: 'src/index.tsx',
output: {
dir: 'dist',
format: 'es',
preserveModules: true,
sourcemap: true,
},
plugins: [
resolve(),
peerDepsExternal(),
commonjs(),
typescript({
tsconfig: 'tsconfig.build.json'
}),
postcss({
minimize: true,
modules: {
generateScopedName: "[hash:base64:5]"
},
plugins: [
postcssUrl({
url: "inline"
})
]
}),
],
};
I hope this config can help others as well
You can checkout this repo. I made some changes for building a lib.
https://github.com/21paradox/react-webpack-typescript-starter
To use a library like below:
import Input from 'my-custom-ui/entry/Input';
import { Input } from 'my-custom-ui';
After doing a lot of searching, I ended up writing a plugin to manually generate the webpack entry code that webpack needed (for building a ui library).
The multiple entry + manualy generated entry file seems to be working for component seperate & no redudant code. This is also very helpful if you want to build a vue based libray.

Exporting sass/css in npm module - Rollup

Overview
I'm trying to write a react based npm module. I've configured my environment using rollup and I can see the js/d.ts/css files being created in the build.
Issue
Using npm link, I was testing in a separate project. Now I'm able to import the js file, but I'm unable to import the css file.
Here is my rollup configuration (rollup.config.js)
import typescript from "rollup-plugin-typescript2";
import commonjs from "rollup-plugin-commonjs";
import external from "rollup-plugin-peer-deps-external";
import resolve from "rollup-plugin-node-resolve";
import sass from 'rollup-plugin-sass';
import pkg from "./package.json";
export default {
input: "src/index.tsx",
output: [{
file: pkg.main,
format: "cjs",
exports: "named",
sourcemap: true
},
{
file: pkg.module,
format: "es",
exports: "named",
sourcemap: true
}
],
plugins: [
external(),
resolve({
browser: true,
extensions: ['.mjs', '.js', '.jsx', '.json', '.scss', '.css']
}),
sass({
output: "autocomplete_style.css"
}),
typescript({
rollupCommonJSResolveHack: true,
exclude: "**/__tests__/**",
clean: true
}),
commonjs({
include: ["node_modules/**"],
namedExports: {
"node_modules/react/react.js": [
"Children",
"Component",
"PropTypes",
"createElement"
],
"node_modules/react-dom/index.js": ["render"]
}
})
]
};
Please note, I'm able to create a successful build. The issue is just with the import of the generated css file.

Webpack Can't resolve other modules while building in my boilerplate project

I've created boilder plate project with webpack, react, typescript etc. but whenever I build my project, webpack throw this errors on my entry point that Cannot resolve other modules (which is just simple Login component)
This is my webpack's error message
ERROR in ./src/index.tsx
Module not found: Error: Can't resolve './components/Login' in '/Users/myname/Desktop/Projects/front/src'
# ./src/index.tsx 6:14-43
This is my index.tsx file
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import Login from './components/Login';
ReactDOM.render(
<BrowserRouter>
<Login />
</BrowserRouter>,
document.getElementById('root')
);
And this is my Login components, which webpack cannot resolve
import * as React from 'react';
export default () => <div>Login</div>;
This is my webpack config and package.json's scripts
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader',
options: {
useCache: true,
reportFiles: ['src/**/*.{ts,tsx}']
}
},
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'template/index.html'
})
],
mode: 'production',
output: {
path: path.resolve(__dirname, 'build/'),
filename: 'bundle.[hash].js'
},
plugins: [new CleanWebpackPlugin()]
};
package.json's scripts
"scripts": {
"build": "webpack"
},
I tried minimize my project as possible so you can focus on this single problem, why the hack my webpack cannot resolve ordinary component file? you can find this minimized project on https://github.com/sh2045/myproblem
you can just clone it, and run
npm i
npm run build
and you can see error message, please help :(
Instead of using awesome-typescript-loader why don't you try the loader's recommended by webpack for typescript
To fix your problem,
Install this node package npm install --save-dev typescript ts-loader. This is the loader that does ts to js conversion.
You need to remove awesome-typescript-loader and use ts-loader in webpack.config.js. Below is the updated webpack.config.js. You can use this configuration and execute npm run build and verify if your webpack bundles the project without errors
Modified webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
plugins: [
new HtmlWebpackPlugin({
template: 'template/index.html'
})
],
mode: 'production',
output: {
path: path.resolve(__dirname, 'build/'),
filename: 'bundle.[hash].js'
},
plugins: [new CleanWebpackPlugin()]
};
Note When i downloaded & setup your project from your git, this package npm i acorn --save was missing in your package.json i believe. so i had to install it manually

Webpack can't find a module 'jquery-form-styler'

In webpack's config file I set 'node_modules' and 'src/js/libs' as folders, where webpack should look for modules. 'jquery-form-styler' is installed via npm and lives in 'node_modules', but according to first error, webpack tries to find module in 'src/js/modules'. Why?
ERROR in ./src/js/modules/forms.js
Module not found: Error: Can't resolve 'jquery-form-styler' in '/Users/ildar.meyker/Sites/html-taxnet/src/js/modules'
# ./src/js/modules/forms.js 5:0-28
# ./src/js/modules/app.js
# ./src/js/main.js
My webpack.config.js content:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: {
main: './src/js/main.js',
metrics: './src/js/metrics.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'public/js')
},
resolve: {
modules: [path.resolve(__dirname, 'src/js/libs'), 'node_modules']
},
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
optimization: {
splitChunks: {
chunks: "all",
minSize: 0
}
}
};
My files structure:
/node_modules/
/src/
js/
libs/
modules/
app.js
...
forms.js
...
main.js
metrics.js
forms.js starts as:
import $ from 'jquery';
import 'jquery.maskedinput';
import 'jquery-validation/jquery.validate';
import 'jquery-validation/additional-methods';
import 'jquery-form-styler';
...
Where 'jquery' and 'jquery-form-styler' are located in 'node_modules', while other modules in 'src/js/libs'.
Looks like webpack's reference to 'src/js/modules' wasn't due to it's attempt to find module in that folder. An error happened, because package.json in 'jquery-form-styles' had an incorrent main attribute. 'jquery.formstyler.min.js' instead of './dist/jquery.formstyler.min.js'.

Categories

Resources