BREAKING CHANGE since webpack 5: The devtool option is more strict - reactjs

I'm setting up react with webpack, here is my webpack config file \n
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.join(__dirname, "src", "index.js"),
devtool: 'sourcemaps',
cache: true,
mode: 'development',
output: {
path:path.resolve(__dirname, "dist"),
filename: './dist/bundle.js'
},
module: {
rules: [
{
test: /\.?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['#babel/preset-env', '#babel/preset-react']
}
}
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, "public/templates/", "budget_account2.html"),
}),
],
}
when i run npm run-script watch then it throw error: \n
Invalid configuration object. Webpack has been initialized using a
configuration object that does not match the API schema.
configuration.devtool should match pattern "^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$".
BREAKING CHANGE since webpack 5: The devtool option is more strict.
Please strictly follow the order of the keywords in the pattern.
Thanks all

It's exactly as the error says.
configuration.devtool should match pattern "^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$".
See a description of the various options here.
To follow it, your devtool value should:
Optionally start with inline-, hidden-, or eval-, depending on where you want the source map to be
Optionally followed by nosources-, if you want the source code to be excluded from the map
Optionally followed by cheap or cheap-module - cheap indicates a fast rebuild time, and module preserves the original lines
Followed by source-map at the end.
Figure out which one(s) of the above you want, construct a string that matches, and use that. For a random example, you could have inline-nosources-cheap-source-map.
(You may also use none, to omit source maps entirely)

Related

How to precompute costly code fragment in advance in React?

We have a React component that uses data provided by some long computation. The provided data (result of a long computation) is always the same (for all users).
What i want to do is to ensure that this computation is executed once (during minification), instead of every time user loads the page.
Webpack uses TerserPlugin for minification by default, when in production mode.
Is TerserPlugin clever enough to figure out that the long computation always returns the same result and optimise it?
If so, is there a way to check that the computation does not execute at runtime? console.log would definitely prevent the optimisation.
If not, maybe another plugins can do that? For example UglifyJS.
Simplified webpack configuration:
...
module.exports = {
mode: 'production',
entry: {
app: ['...'],
},
output: {
path: '...',
filename: "[name].bundle.js",
publicPath: "/"
},
module: {
rules: [
{
test: /\.html$/,
loader: "file-loader?name=[name].[ext]"
},
{
test: /\.(jsx?|tsx?)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
}
},
...
]
},
resolve: {
extensions: [.ts", ".tsx", ".js", ".jsx"],
modules: [
path.join(__dirname, "./src"),
]
},
};
The only way i can imagine is to create a script that creates a json file with desired data
Is this a good solution or is there a better, simpler one? Some downsides are for example: linter may complain that imports don't exist, more complicated setup.
Here is a demo with example use case.
If the data is the same within all the users, you should cache the data on the backend if a backend is present.
If the data is unique the each client but you want the client to do less computing, look at react.memo.

Migration Webpack from version 1 to 2

I want to convert webpack 1 configuration file to webpack 2 version.
In addition, I want to exclude node modules from bundle.
I got following Exception
Using removed Babel 5 option: base.modules - Use the corresponding module transform plugin in the plugins option. Check out http://babeljs.io/docs/plugins/#modules
In addition, I get another error
ERROR in ./index.js
Module parse failed: Unexpected token (9:16)
You may need an appropriate loader to handle this file type.
The errors seem informative but I can't find what is wrong.
Do I miss something from migration guide?
Version 1
const config = {
entry: './index.js',
output: {
path: '/',
filename: 'bundle.js',
},
devServer: {
inline: true,
port: 8080
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
}
};
module.exports = config;
Version 2
const config = {
entry: './index.js',
output: {
path:'/',
filename: 'bundle.js',
},
devServer: {
inline: true,
port: 8080
},
module: {
rules:[
{
test:/\.jsx?$/,
use:[
{
loader:'babel-loader',
options:{
only:['/node_modules/'],
presets:['es2015', 'react']
},
}
]
}
]
}
};
module.exports = config;
For the first error with Babel, you likely have a dependency that still uses Babel 5 and it contains a config that is no longer allowed in Babel 6. That probably happens because you're trying to transpile your node_modules, as you have removed the exclude option, which has not been changed in webpack 2. Babel always uses the closest config it can find.
For the second error, you are using some syntax that requires Babel, presumably JSX. But you have set the only option on babel-loader, which tells Babel to only transpile files that match the given path. Hence, it's only applied to the node_modules, not the rest of your project. That is exactly the opposite of what you wanted.
Your .jsx rule should be:
{
test:/\.jsx?$/,
exclude:/node_modules/,
use:[
{
loader:'babel-loader',
options:{
presets:['es2015', 'react']
},
}
]
}
You are also setting the output.path to /. That is the root of your file system, not the root of your project. To use the directory where the webpack config is, you can use Node's __dirname, which is the absolute path to the directory of the currently executed file (i.e. webpack.config.js).
output: {
path: __dirname,
filename: 'bundle.js',
},

URIError: Failed to decode param '/%PUBLIC_URL%/ WEBPACK

I have a problem running my react application with webpack, I have this error:
URIError: Failed to decode param '/%PUBLIC_URL%/src/css/TagsCheck.css'
at decodeURIComponent (<anonymous>)
and this is my webpack.config.js:
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
var publicUrl = '/public';
module.exports = {
context: path.join(__dirname, "src"),
devtool: debug ? "inline-sourcemap" : false,
entry: "./index.js",
devServer: {
host: '0.0.0.0',
port: 8080,
inline: true
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: ['react-html-attrs', 'transform-decorators-legacy', 'transform-class-properties'],
}
}
]
},
output: {
path: __dirname + "/src/",
filename: "client.min.js"
},
plugins: debug ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }),
// new HtmlWebpackPlugin({
// pkg: require("./package.json"),
// template: 'template.html',
// inject: false
// }),
// Makes the public URL available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
new InterpolateHtmlPlugin({
PUBLIC_URL: publicUrl
// You can pass any key-value pairs, this was just an example.
// WHATEVER: 42 will replace %WHATEVER% with 42 in index.html.
}),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: path.resolve('public/index.html'),
}),
],
};
I want that in my index file can read the value of /%PUBLIC_URL%/.
What I have to do to make running my code?
And I have another question...
I am using react and I am importing the library react-native, Will I have some problem with the var PUBLIC_URL?
I can make the app easly only importing the 'react-native' library?
Thanks so much.
Regards,
It could be related to encoding of spaces (ISO hex %20) somewhere in your project, take a look at this Github issue comment: https://github.com/facebook/create-react-app/issues/4150#issuecomment-379742880
Disclaimer: I'm not familiar with how InterpolateHtmlPlugin() works and the best practices associated with it. However, I think that Babel is tripping up on the % char. What if you used the actual path instead. Maybe this answer will be of some help.
Another option would be to include the TagsCheck.css as part of the HtmlWebpackPlugin({ ... }) in your webpack config. Then that file would be copied to your output directory and the %PUBLIC_URL% should no longer be necessary to reference it as it would be in the root relative to the file that references it.
It may also be necessary to add another rule to your webpack.config.js:
//...
{
test: /\.css$/,
exclude: /node_modules/,
use: ['style-loader', 'css-loader']
// The filename should be preserved, if not then tack on ?name=[name].[ext] to either loader
// e.g. 'style-loader?name=[name].[ext]' ...
}
//...
Your setup is different enough from mine I could not test my suggestions. Sorry if I missed something and am way off. However, I hope they help someone!

webpack file-loader options aren't recognized

Being new to webpack, the answer might be staring me down but I don't see it. No matter how I try to pass them along, the file-loader options aren't found.
I'm using file-loader and I'm trying to pass a publicPath (or simply anything, at first) along as an option. I went into the file loader source code and added a log for all the options it detected, but they always come up empty.
webpack.config.prod.js
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: [
'./src/index.js'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'idlink-1.1.1.js',
publicPath: ''
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'})
],
module: {
loaders: [
{
exclude: /node_modules/,
loader: 'babel',
query: { presets: ['react', 'es2015', 'stage-1'] }
},
{test: /\.css$/, loader: "style-loader!css-loader" },
{test: /\.scss$/, loaders: ["style", "css", "sass"]},
{test: /\.less$/, loader: "style-loader!css-loader!less-loader" },
{
test: /\.(jpe?g|png|gif|svg|pdf)$/i,
loader: "file",
options: { publicPath: 'https://apps.ixordocs.be/'}
},
{test: /\.gif$/, loader: "url-loader?mimetype=image/png" }
]
},
}
I've also tried with
loader: "file-loader"
as well as added the options as one string like this
loader: "file?name=[name].[ext]&publicPath=https://apps.ixordocs.be/"
Some context info:
I don't want to have a hardcoded publicPath defined in my output: {}, i want to grab it dynamically from a parameter placed on the div that my plugin is loaded into.
I've tried using the __webpack_public_path__ variable and it works, but not for images. The public path is grabbed from the parameter, set, and used to fetch a chunk. Somehow it has no effect on images though. If I hardcode a publicPath under output, it DOES work for images. This leads me to believe there is a problem with the loader's communication to the variable, so the idea is to get the options working and eventually try to pass a dynamic publicPath in there.
Your question is totally valid based on the documentation of the loader on both loader's GitHub repo and webpack docs. The problem is the publicPath and outputPath features are implemented in a pull request that is merged but not yet released to a new version of loader, and the README on npm doesn't mention the features for the same reason.
You can still use these features by installing from the GitHub repo with npm install webpack/file-loader --save-dev and your options should work. If not try replacing options with query.
{
test: /\.(jpe?g|png|gif|svg|pdf)$/i,
loader: "file-loader",
query: { publicPath: 'https://apps.ixordocs.be/'}
}
Using URLs for publicPath is also valid because it happens often that you want to load your assets from a CDN or another server.

Why is my Webpack ReactJS App so large?

I have followed as many tips as I can find in packaging my Webpack ReactJS app for production. Unfortunately, the file size is still 3MB. What am I doing wrong?
Here is my Webpack Config file:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'./index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle-webpack.js',
publicPath: './'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true,
warnings: false
}
})
],
module: {
loaders: [
{
test: /\.js$/,
loaders: [ 'babel' ],
exclude: /node_modules/,
include: __dirname
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{test: /node_modules\/react-chatview/, loader: 'babel' }
]
}
}
Any help would be greatly appreciated!
I use the following command to package it:
> NODE_ENV=production webpack -p
I get the following output:
bundle-webpack.js 3.1 MB 0 [emitted] main
Best,
Aaron
Looks like you've still got a fair amount of dev stuff there, e.g. hot module replacement.
Take a look at webpack.config.prod.js at React Transform Boilerplate as a guide.
You may also be able to optimise your imports by including only the parts of the packages you need and leaving out the rest. See: Reduce Your bundle.js File Size By Doing This One Thing .
So, it turns out that David L. Walsh was correct that I had too much development stuff in my app. However, the answer provided did not resolve the issue.
I resolved the issue using 3 steps.
Remove all the "hot-reloading" plugins from my webpack configuration, as David instructed.
Remove the hot reloading "react-transform" plugin from my .babelrc file.
Change the "devtool" parameter to "source-map" from "cheap-module-eval-source-map"
After following those steps, the final bundle file was 340kb while the source map was still 3MB. Fortunately, I don't have to include the source map in my application, so it can be downloaded at 340kb, which is still fairly large, but reasonable for modern browsers running on modern internet connections.
I would up-vote David's answer, but I don't have enough reputation points yet to do so.

Resources