After publish react in npm can't load chunks of react.lazy - reactjs

I have a CRA react project where i'm using react.lazy to split the code. I'm currently working on publish it in npm as a react component.
For compilate the code i'm using Craco. Here is the configuration of it:
const CracoLessPlugin = require('craco-less');
const path = require('path');
const PACKAGE_NAME = 'name'
const CSS_FILE_NAME = 'main.css';
module.exports = {
webpack: {
configure: (webpackConfig, { paths }) => {
const buildFolder = path.resolve(__dirname, 'build');
paths.appBuild = buildFolder;
webpackConfig.externals = {
...webpackConfig.externals,
react: {
commonjs: 'react',
commonjs2: 'react',
amd: 'react',
root: 'React',
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'react-dom',
root: 'ReactDOM',
}
};
webpackConfig.plugins[5].options.filename = CSS_FILE_NAME;
webpackConfig.plugins[5].options.linkType = 'text/css'
return {
...webpackConfig,
output: {
...webpackConfig.output,
path: buildFolder,
filename: 'main.js',
library: PACKAGE_NAME,
libraryTarget: 'umd',
umdNamedDefine: true,
publicPath: `/`,
},
optimization: {
...webpackConfig.optimization,
runtimeChunk: false,
splitChunks: {
...webpackConfig.optimization.splitChunks,
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
},
},
},
};
},
},
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
javascriptEnabled: true,
}
}
}
]
};
I managed to publish it correctly but when i'm importing it in other react project, I can't manage to load the chunks. I always got something like this
This is happening for js and css files.
I think that the problem is related to the public_path of the output configuration of webpack, but i can't find the correct value for it to make this work.
I can give you more information about other related configuration if asked.
Thank you for the help.

Related

React hook error when use built package from webpack

I've making a library and tried to use built package on example code by doing this
import { createMiddleware, useActionListener } from "../../../../lib";
It occurs an error Invalid hook call. at
useActionListener("SUB", (action) => {
//...
});
So I tried to publish a package and changed like this
import { createMiddleware, useActionListener } from "myLibraryName";
And it works like charm.
I have no idea why calling built package direct occurs an error. Any ideas?
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, 'lib'),
filename: 'index.js',
libraryTarget: 'umd',
library: 'reactActionListener',
globalObject: 'this',
},
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
},
redux: {
root: 'Redux',
commonjs2: 'redux',
commonjs: 'redux',
amd: 'redux',
},
},
resolve: {
extensions: ['.ts', '.js', '.json', '.tsx', '.jsx'],
alias: {
// Needed when library is linked via `npm link` to app
react: path.resolve('./node_modules/react'),
},
},
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
module: {
rules: [
{
test: /\.(js|ts|tsx|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
};

Webpack generating [hash].worker.js file when packaging custom library

I'm trying to create a library of reusable react components for our internal use.
Webpack is bundling the output - which should be a single file. But it's actually putting out the bundle.js that I'd expect plus a file called [some_hash].worker.js.
I'm not sure how to force webpack to include that "worker" file with the single bundle that I'm asking it for.
The webpack.config:
const path = require('path');
const webpack = require('webpack');
const DIST_PATH = path.resolve(__dirname, "../dist");
const SRC_PATH = path.resolve(__dirname, "../src");
const APP_PATH = path.resolve(__dirname, "../src/index.js");
const BASE_PATH = path.resolve(__dirname);
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = ({ appPath = APP_PATH, distPath = DIST_PATH }) => ({
context: BASE_PATH,
devServer: {
contentBase: distPath,
compress: true,
port: 9000,
historyApiFallback: true
},
resolve: {
modules: ['node_modules', SRC_PATH],
alias: {
'react': path.resolve(__dirname, '../node_modules/react'),
'react-dom': path.resolve(__dirname, '../node_modules/react-dom'),
}
},
externals: {
// Don't bundle react or react-dom
react: {
commonjs: "react",
commonjs2: "react",
amd: "React",
root: "React"
},
"react-dom": {
commonjs: "react-dom",
commonjs2: "react-dom",
amd: "ReactDOM",
root: "ReactDOM"
}
},
entry: {
bundle: appPath,
},
output: {
path: distPath,
filename: 'index.js',
publicPath: '/dist/',
library: 'internal-components',
libraryTarget: 'umd',
umdNamedDefine: true
},
module: {
rules: [
{
test: /\.jsx$/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: [
'#babel/plugin-proposal-object-rest-spread',
'#babel/plugin-syntax-dynamic-import',
[ '#babel/plugin-proposal-decorators', { 'legacy': true } ],
[ '#babel/plugin-proposal-class-properties', { 'loose': true } ]
]
}
}
},
{
test: /\.js$/,
exclude: /(node_modules|build)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
plugins: [
'#babel/plugin-proposal-object-rest-spread',
'#babel/plugin-syntax-dynamic-import',
['#babel/plugin-proposal-decorators', {'legacy': true}],
["#babel/plugin-proposal-class-properties", {'loose': true}]
]
}
}
},
...
]
},
plugins: [
new CleanWebpackPlugin(),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
})
]
});
You might try using the worker-loader plugin with inline to handle the bundling -
rules: [
...
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: { inline: true, fallback: false }
}
}
]
That said, there are several open issues on Github surrounding using the worker as a blob, so YMMV
Actually if you are using webpack 3 and above, chunking of the bundle is automatically done for you. In the SplitChunks Plugin documentation here it is actually stated how this behaves.
So because of this you might need to scan your code and check for this conditions. Also it's good to know if you are asynchrously importing the some module? That might signal webpack to make it into a separate chunk.

How to use webpack in hot mode

i'm using in my react project a library that needs to be compiled using webpack ( the library called storm-react-diagrams)
the problem is , whenever i do some changes in the library , i need to compile it using webpack , then restart the react app using npm start in order for the changes to take effect (the generated bundle.js doesn't get updated untill i use npm start ) .
How can i optomize this and just refresh the page automaticly whenever i edit the app or the library
for info :
I'm using VS code
when changing and saving a file on my react app , the page on the browser reloads and changes take effect with no problem .
unfortuanatly , this doesn't happen when i change a file in node_modules folder
webpack config file
const webpack = require("webpack");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
var path = require("path");
var plugins = [];
const production = process.env.NODE_ENV === "production";
//do we minify it all
if (production) {
console.log("creating production build");
plugins.push(
new webpack.DefinePlugin({
"process.env.NODE_ENV": '"development"'
})
);
}
/**
* #author Dylan Vorster
*/
module.exports =
//for building the umd distribution
{
entry: "./src/main.ts",
output: {
filename: "main.js",
path: __dirname + "/dist",
libraryTarget: "umd",
library: "storm-react-diagrams"
},
externals: {
react: {
root: "React",
commonjs2: "react",
commonjs: "react",
amd: "react"
},
"react-dom": {
root: "ReactDOM",
commonjs2: "react-dom",
commonjs: "react-dom",
amd: "react-dom"
},
lodash: {
commonjs: "lodash",
commonjs2: "lodash",
amd: "_",
root: "_"
}
},
plugins: plugins,
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader"
},
{
test: /\.tsx?$/,
loader: "ts-loader"
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
devtool: production ? "source-map" : "cheap-module-source-map",
};

Can't import a module in my crafted module

I did a slider on mobx and bundle it using webpack 3. I excluded mobx from slider's bundle using "externals". Then I published it as package, created a mobx-sandbox and installed the slider there.
In result I'm getting an error because package can't import mobx.
But I expecting that slider will find mobx because I imported it on sandbox page.
I also receiving in console:
[mobx] Warning: there are multiple mobx instances active.
This might lead to unexpected results.
What am I missing?
slider's webpack.config:
var path = require('path');
var webpack = require('webpack');
module.exports = {
node: {
fs: "empty" // https://github.com/josephsavona/valuable/issues/9
},
devtool: 'source-map',
entry: {
bundle: [ "./src/index.js" ]
},
output: {
path: path.join(__dirname, "lib"),
filename: "index.js"
},
externals: {
'react': {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react'
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom'
},
'mobx': {
root: 'mobx',
commonjs2: 'mobx',
commonjs: 'mobx',
amd: 'mobx'
},
'mobx-react': {
root: 'mobx-react',
commonjs2: 'mobx-react',
commonjs: 'mobx-react',
amd: 'mobx-react'
}
},
stats: {
colors: true,
reasons: true
},
resolve: {
extensions: ['.js']
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /\/node_modules\//,
loader: 'babel-loader',
query: {
cacheDirectory: true
}
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
]
};
slider's .babelrc
{
"presets": ["es2015", "react", "stage-0"],
"plugins": ["transform-decorators-legacy"]
}
slider repository:
https://github.com/andiwilflly/rslider
sandbox repository:
https://github.com/SkunSHD/rslider-test-sandbox
The problem was with absence of umd's imports in bundle.
This line in output helped to import modules in bundle properly:
webpack.config:
module.exports = {
... ,
output: {
... ,
libraryTarget: 'umd'
}
}

Creating React component for distribution results in much larger build than expected

I've loosely followed this link to create my react components for distribution. My webpack production build is below.
However my build comes out much larger than I would expect it to considering that the individual file sizes combined are somewhere around 1/10th the size. Specifically my file sizes for the source js and less files, combined is only 1.6kb. However the build is ~10x more at 13kb.
My components are extremely simple and similar. I have a FlexTable, a FlexTableRow and a FlexTableCell file. All of them have the same signature as below but with a different style.less. In my style.less it is basically a few lines of css that say display: flex; flex: 0 etc etc. So to summarize, very minimal js and very minimal amounts of css.
So the question is, why does the production build balloon to 13kb from 1.6kb? What am I doing wrong?
my-flex-table.js
var React = require('react');
const styles = require('./my-flex-table.less')
const FlexTable = (props) => (
<section {...props} className={styles['my-flex-table'] + " " + props.customStyles}>{props.children}</section>
)
module.exports = FlexTable;
(Replace FlexTable with FlexTableRow or FlexTableCell in the above and you have my other files)
My package.json points to an index file that simply exports all 3 of these with module.exports = {FlexTable, FlexTableCell, FlexTableRow}
The webpack production script is run with:
NODE_ENV=production node_modules/webpack/bin/webpack.js --config webpack.config.prod.js
Webpack production script
var autoprefixer = require('autoprefixer');
var postcssImport = require('postcss-import');
var webpack = require('webpack');
module.exports = {
entry: './src/index.jsx',
output: {
filename: './dist/my-flex-table.js',
library: 'MyFlexTable',
libraryTarget: 'umd',
},
resolve: {
extensions: ['', '.js', '.jsx', '.less']
},
module: {
loaders: [
{ test: /.jsx?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
cacheDirectory: true,
plugins: ['transform-runtime'],
presets: ['es2015', 'stage-0','react']
},
"env": {
"production": {
"presets": ["react-optimize"]
}
}
},
{ test: /.less$/, loader: 'style-loader!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader!less-loader' },
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/, loader: 'url-loader?limit=100000' }
]
},
postcss: function (wp) {
return [postcssImport({
addDependencyTo: wp
}),autoprefixer];
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
unused: true,
dead_code: true,
drop_console: true,
warnings: false
}
})
],
externals: [
{
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
},
},
{
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom',
},
},
]
};
The webpack visualizer is a good tool to troubleshoot bundle sizes. Follow the instructions there and it might help you see what extra is getting bundled in that you might not be intending.

Resources