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.
Related
Hi guys I have an issue with my css in the react project
I have a component called header.jsx and the header.scss file is imported in it, so I want the css to be applied from header.scss only not from any other file (even though the className names are same).
There is a way to wrap around with a div and provide unique className,or use css-modules but can the same be done with webpack configuration ? I tried to change a bit but couldn't let it happen.
Below is my webpack config for the project
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
plugins: [
new HtmlWebpackPlugin({ template: "./public/index.html" }),
new MiniCssExtractPlugin(),
],
output: {
path: path.join(__dirname, "/dist"),
filename: "index.bundle.js",
},
resolve: {
extensions: [".js", ".jsx"],
},
devServer: {
static: path.resolve(__dirname, "dist"),
port: 9000,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /nodeModules/,
resolve: {
extensions: [".js", ".jsx"],
},
use: {
loader: "babel-loader",
},
},
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true,
},
},
"sass-loader",
],
},
],
},
};
I have a React TypeScript project that uses webpack 5.
I am trying to get a runtime-config.js file that I can change out in production by importing it as decribed in a similar Vuejs Docker issue.
I wanted to use File Loader but found that it's been deprecated in webpack 5
Here's what I want to achieve:
have ./runtime-config.js non bundled so that I can refer to it on the window object
easily reference that file in React (TypeScript) so that this dynamic configuration can be read.
Any help is appreciated.
Below is my webpack configuration:
// webpack.config.js
import path from 'path'
import { Configuration as WebpackConfiguration, DefinePlugin, NormalModuleReplacementPlugin } from 'webpack'
import { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server';
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
import ESLintPlugin from 'eslint-webpack-plugin'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
const CopyPlugin = require('copy-webpack-plugin');
interface Configuration extends WebpackConfiguration {
devServer?: WebpackDevServerConfiguration;
}
const config: Configuration = {
mode: 'development',
target: 'web',
devServer: {
static: path.join(__dirname, 'build'),
historyApiFallback: true,
port: 4000,
open: true,
liveReload: true,
},
output: {
publicPath: '/',
path: path.join(__dirname, 'dist'),
filename: '[name].bundle.js',
},
entry: {
main: './src/index.tsx',
'pdf.worker': path.join(__dirname, '../node_modules/pdfjs-dist/build/pdf.worker.js'),
},
module: {
rules: [
{
test: /\.(ts|js)x?$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-env',
'#babel/preset-react',
'#babel/preset-typescript',
],
},
},
},
{
test: /\.(sa|sc|c)ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader',
{
loader: 'postcss-loader', // postcss loader needed for tailwindcss
options: {
postcssOptions: {
ident: 'postcss',
plugins: [tailwindcss, autoprefixer],
},
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
outputPath: '../fonts',
},
},
{
test: /runtime-config.js$/,
use: [
{
loader: 'file-loader',
options: {
name: 'runtime-config.js',
},
},
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
}),
new NormalModuleReplacementPlugin(
/^pdfjs-dist$/,
(resource) => {
// eslint-disable-next-line no-param-reassign
resource.request = path.join(__dirname, '../node_modules/pdfjs-dist/webpack.js')
},
),
new CopyPlugin({
patterns: [
// relative path is from src
{ from: 'public/images', to: 'images' },
],
}),
// Add type checking on dev run
new ForkTsCheckerWebpackPlugin({
async: false,
}),
// Environment Variable for Build Number - Done in NPM scripts
new DefinePlugin({
VERSION_NUMBER: JSON.stringify(process.env.VERSION_NUMBER || 'development'),
}),
// Add lint checking on dev run
new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx'],
}),
],
devtool: 'inline-source-map',
};
export default config
I have a fairly standard lerna monorepo setup, using yarn workspaces and TypeScript.
There are pacakge folders for various services and also the React frontend. I've been migrating the Webpack config to Webpack 5 so that I can take advantage of the module federation. The React app is complex, uses CSS modules with scss, TypeScript, etc so the config is relatively complex, nevertheless I feel as if I am there with compilation. That notwithstanding there are 2 issues that I cannot seem to fathom, the most problematic of them being that webpack seems to be trying to load files from other packages in the monorepo (and these are causing TypeScript/eslint errors).
Webpack.config.js
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");
const isDevelopment = process.env.NODE_ENV === "development";
const imageInlineSizeLimit = 2000;
// Default js and ts rules
const tsRules = {
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: path.resolve(__dirname, "src"),
exclude: [/node_modules/],
loader: "babel-loader",
options: {
customize: require.resolve("babel-preset-react-app/webpack-overrides"),
presets: [
"#babel/preset-env",
"#babel/preset-react",
"#babel/preset-typescript",
],
plugins: [],
},
};
// Process any JS outside of the app with Babel.
// Unlike the application files, we only compile the standard ES features.
const externalJsRules = {
test: /\.(js|mjs)$/,
exclude: [/node_modules/],
loader: "babel-loader",
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
[
require.resolve("babel-preset-react-app/dependencies"),
{ helpers: true },
],
],
cacheDirectory: true,
cacheCompression: false,
},
};
let plugins = [
new ForkTsCheckerWebpackPlugin({
async: false,
}),
new ESLintPlugin({
extensions: ["js", "jsx", "ts", "tsx"],
}),
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
chunkFilename: "[id].[contenthash].css",
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public", "index.html"),
}),
new webpack.IgnorePlugin({
// #todo: this prevents webpack paying attention to all tests and stories, which probably ought only be done on build
resourceRegExp: /(coverage\/|\.spec.tsx?|\.mdx?$)/,
}),
];
if (isDevelopment) {
// For use with dev server
tsRules.options.plugins.push("react-refresh/babel");
externalJsRules.options.sourceMaps = true;
externalJsRules.options.inputSourceMap = true;
plugins = [...plugins, new webpack.HotModuleReplacementPlugin()];
}
module.exports = {
entry: path.resolve(__dirname, "src", "index.tsx"),
output: {
path: path.resolve(__dirname, "build"),
publicPath: "/",
clean: true,
},
module: {
rules: [
externalJsRules,
tsRules,
{
test: [/\.avif$/],
loader: "url-loader",
options: {
limit: imageInlineSizeLimit,
mimetype: "image/avif",
name: "static/media/[name].[hash:8].[ext]",
},
},
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: "url-loader",
options: {
limit: imageInlineSizeLimit,
name: "static/media/[name].[hash:8].[ext]",
},
},
{
test: /\.svg$/,
use: ["#svgr/webpack", "url-loader"],
},
{
test: /\.s?css$/,
oneOf: [
{
test: /\.module\.s?css$/,
use: [
isDevelopment
? // insert css into DOM via js
"style-loader"
: // insert link tags
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true,
sourceMap: isDevelopment,
importLoaders: 2,
},
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-flexbugs-fixes",
[
"postcss-preset-env",
{
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
},
],
"postcss-normalize",
],
},
},
},
{
loader: "sass-loader",
options: {
sourceMap: isDevelopment,
},
},
],
},
{
use: [
isDevelopment
? // insert css into DOM via js
"style-loader"
: // insert link tags
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: isDevelopment,
importLoaders: 2,
},
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-flexbugs-fixes",
[
"postcss-preset-env",
{
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
},
],
"postcss-normalize",
],
},
},
},
{
loader: "sass-loader",
options: {
sourceMap: isDevelopment,
},
},
],
},
],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".scss"],
symlinks: false,
// don't provide polyfills for non UUI-core
fallback: {
// crypto: false,
// fs: false,
// stream: false,
// path: false,
},
},
optimization: {
runtimeChunk: true,
},
plugins: [...plugins],
devtool: "eval-cheap-module-source-map",
devServer: {
static: path.join(__dirname, "build"),
historyApiFallback: true,
port: 3000,
open: true,
hot: true,
},
};
Webpack is run from the frontend package folder. Also I have scanned the code for any refrences to other packages in the React code, but there are none, so I can't understand why this is loading and how to prevent them loading.
Example error:
ERROR in ../../node_modules/#githubpackage/src/aFile.ts:2:25
TS2801: This condition will always return true since this 'Promise<boolean>' is always defined.
Help much appreciated (I realise the issue should be fixed too ;p).
[EDIT] I've edited the error to indicate that the problematic package is the only package that I am installing via github packages (in a couple of the other monorepo packages).
ALSO I edited the entry file so that it only imported React and ReactDOM and rendered a <p> tag and webpack still tried loading this package... so unless there is something wrong with the webpack config, this is some odd behaviour.
I am trying to use froala editor in my react code and It is working perfectly in my local. But in production it is crashing. It is just a blank page. When I opened console there is a error message Super expression must either be null or a function not undefined. If I remove froala editor then it is working fine.
import React from 'react';
import 'froala-editor/css/froala_style.min.css';
import 'froala-editor/css/froala_editor.pkgd.min.css';
import FroalaEditorComponent from 'react-froala-wysiwyg';
const Editor = (props) => {
return <FroalaEditorComponent {...props} />;
};
export default Editor;
and this is my webpack config
const webpack = require('webpack');
const path = require('path');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
mode: 'production',
entry: {
main: ['./client/app/main'],
},
externals: {
react: 'React',
'react-dom': 'ReactDOM'
},
output: {
path: path.resolve(__dirname, './client/dist'),
filename: '[name].app.bundle.js',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.html$/,
loader: 'file-loader?name=[name].[ext]',
},
{
test: /\.js?$/,
exclude: /node_modules[\/\\](?!(swiper|dom7|#jimp\/core|d3-array|d3-scale|file-type|react-wordcloud|striptags)[\/\\])/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
babelrc: false,
presets: ['#babel/preset-env', '#babel/react'],
plugins: [
['#babel/plugin-proposal-decorators', { 'legacy': true }],
'#babel/plugin-proposal-optional-chaining',
'#babel/plugin-proposal-class-properties',
]
},
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
},
],
},
resolve: {
modules: [path.resolve(__dirname, './client/app'), 'node_modules'],
extensions: ['.jsx', '.js', '.json'],
// These extensions are tried when resolving a file
enforceExtension: false,
// If false it will also try to use no extension from above
moduleExtensions: ['-loader'],
// These extensions are tried when resolving a module
enforceModuleExtension: false,
},
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new CompressionPlugin({
test: /\.js?$/,
deleteOriginalAssets: true,
})
],
node: {
fs: 'empty'
}
};
Any help would be really thankfull
Inside my index.js I am using webpack-dev-middleware/webpack-hot-middleware where I require my webpack.config and use it for compiler.
index.js
const webpack = require('webpack')
const webpackConfig = require('../../webpack.config.js')
const compiler = webpack(webpackConfig)
const webpackDevMiddleware = require('webpack-dev-middleware')
app.use(webpackDevMiddleware(compiler, {
publicPath: webpackConfig.output.publicPath,
hot: true,
noInfo: true,
stats: {
colors: true
}
}))
app.use(require('webpack-hot-middleware')(compiler))
I try to export my webpack.config using Common.js by require and module.exports but I get error
TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
webpack.config
'use strict'
const path = require('path')
const webpack = require('webpack')
const publicPath = path.resolve(__dirname, './src/client')
const buildPath = path.resolve(__dirname, './src')
process.noDeprecation = true
module.exports = {
devtool: 'source-maps',
performance: {
hints: false
},
context: publicPath,
entry: {
bundle: [
'react-hot-loader/patch',
'webpack-hot-middleware/client?reload=false&noInfo=true',
'script-loader!jquery/dist/jquery.min.js',
'script-loader!tether/dist/js/tether.min.js',
'script-loader!bootstrap/dist/js/bootstrap.min.js',
'./app.js'
]
},
output: {
path: path.join(buildPath, 'dist'),
filename: '[name].js',
publicPath: '/'
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
CountdownForm: path.resolve(__dirname, 'src/client/scenes/countdown/components/CountdownForm.jsx'),
Countdown: path.resolve(__dirname, 'src/client/scenes/countdown/index.jsx'),
..
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules|dist|build/,
loader: 'babel-loader',
options: {
plugins: [
[
'babel-plugin-react-css-modules',
{
context: publicPath,
filetypes: {
'.scss': 'postcss-scss'
}
}
]
]
}
},
{
test: /\.local\.(css|scss)$/,
use: [
'style-loader',
'css-loader?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
'postcss-loader',
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
resources: path.resolve(__dirname, './src/client/styles/global/sass-resources.scss')
}
}
]
},
{
test: /^((?!\.local).)+\.(css|scss)$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
jquery: 'jquery'
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development')
}
})
]
}
If I use ES6 (I am using babel and this usually works) using import statements at the top instead of require and export default instead of module.exports I get this error
Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration misses the property 'entry'.
All of this is because of modules:false inside my .babelrc If I remove that Common.js way works, but I need this. How can I export webpack.config to compiler using modules:false
{
"presets": [
"react",
["es2015", { "modules": false }],
"stage-0"
],
"plugins": [
"react-hot-loader/babel",
"transform-runtime"
]
}
transform-runtime adds import and that results in mixing import with your module.exports.
Simple fix would be to replace module.exports with es6 export
module.exports = { ...webpackconfig }
becomes
export default { ...webpackconfig }
and update your index.js to use default export
const webpackConfig = require('../../webpack.config.js').default
You can find more information about this on these issues
https://github.com/webpack/webpack/issues/4039
https://github.com/webpack/webpack/issues/3917