I'm using webpack for my build which works without any problems using the webpack-dev-server (npm run watch), however when I try to create a production build (npm run build) I seem to get the error in the console when I try to load the website and nothing shows up at all on-screen.
Uncaught Error: [HMR] Hot Module Replacement is disabled.
I have a few questions about this:
My understanding of using Hot Module Replacement is that its designed for making life easier during development, it should not be used in production deployments. Is that correct?
Given the below, why is Hot Module Replacement is being used? I don't see what's driving it.
What's the best practice when it comes to production builds, should I have a separate webpack config for prod and dev? Ideally I'd like to make use of a single config purely to ease maintenance.
package.json
{
// ...
"scripts": {
"build": "webpack --progress --colors --production",
"watch": "webpack-dev-server --inline --hot --progress --colors"
},
"dependencies": {
"bootstrap": "^3.3.6",
"bootstrap-sass": "^3.3.6",
"bootstrap-webpack": "0.0.5",
"extract-text-webpack-plugin": "^1.0.1",
"html-webpack-plugin": "^2.15.0",
"jquery": "^2.2.3",
"node-sass": "^3.4.2",
"react": "^15.0.1",
"react-bootstrap": "^0.28.5",
"react-dom": "^15.0.1",
"react-redux": "^4.4.1",
"react-router": "^2.0.1",
"react-router-redux": "^4.0.1",
"redux": "^3.3.1",
"redux-thunk": "^2.0.1",
"webpack": "^1.12.14"
},
"devDependencies": {
"babel-core": "^6.7.4",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"css-loader": "^0.23.1",
"exports-loader": "^0.6.3",
"file-loader": "^0.8.5",
"imports-loader": "^0.6.5",
"less": "^2.6.1",
"less-loader": "^2.2.3",
"redux-devtools": "^3.2.0",
"redux-logger": "^2.6.1",
"sass-loader": "^3.2.0",
"style-loader": "^0.13.1",
"url-loader": "^0.5.7",
"webpack-dev-server": "^1.14.1"
}
}
webpack.config.js
var webpack = require('webpack');
var htmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
entry: [
'webpack/hot/only-dev-server',
path.resolve(__dirname, 'app/index.js')
],
output: {
path: path.resolve(__dirname, 'public'),
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel', query: { presets: [ 'es2015', 'react' ] } },
{ test: /\.scss$/, loader: 'style!css!sass?includePaths[]=' + path.resolve(__dirname, './node_modules/bootstrap-sass/assets/stylesheets/') },
{ test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, loader: 'file' }
]
},
resolve: {
modulesDirectories: ['node_modules']
},
plugins: [
new webpack.NoErrorsPlugin(),
new htmlWebpackPlugin({
filename: 'index.html',
template: './index.html',
inject: false
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new webpack.optimize.OccurenceOrderPlugin()
]
};
You need to enable the HMR plugin. Add the HotModuleReplacementPlugin to your plugins array in you webpack.config. You can have a separate webpack.config for dev and production.
Something like
plugins: [
new webpack.NoErrorsPlugin(),
new htmlWebpackPlugin({
filename: 'index.html',
template: './index.html',
inject: false
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin()
]
It's not a particularly good idea to include the hot loading bits in a production build. They are practically useless there and just bloat your file size.
There are multiple strategies on how to deal with this. Some people separate their webpack configuration per file and then point to it through --config. I prefer to maintain a single file and branch through npm. I use webpack-merge to share configuration between branches (disclaimer: I'm the author).
I got this error due to the fact that I had code like this in webpack.config.js.
devServer: {
...
hot: true,
inline: true
}
Used the command webpack-dev-server --hot --inline instead and then I did not have to bloat my config with new webpack.HotModuleReplacementPlugin().
https://github.com/webpack/webpack/issues/1151#issuecomment-111972680
You will need to enable Hot Module Replacement feature to have it working e.g:
webpack.config.js
module.exports = {
//...
devServer: {
hot: true
},
plugins: [
//...
new webpack.HotModuleReplacementPlugin()
]
};
From webpack:
Note that webpack.HotModuleReplacementPlugin is required to fully enable HMR. If webpack or webpack-dev-server are launched with the --hot option, this plugin will be added automatically, so you may not need to add this to your webpack.config.js. See the HMR concepts page for more information.
As said, otherwise you can enable it through package.json add --hot to your script e.g.
"start": "webpack-dev-server --hot",
Related
I have been struggling with an issue with hot reloading where making edits in certain files would reload the app without those changes.
My initial solution was to update webpack and related modules. The first module I updated was webpack-dev-server. I went from v3 to v4 which immediately broke the app. All images and json files were getting 404'd when running the dev server.
Here is the original package.json:
{
...
"scripts": {
"dev": "set NODE_ENV=development && webpack serve --config config/webpack.dev.js --open",
"build": "set NODE_ENV=production && webpack --config config/webpack.prod.js",
"beatmarkers": "babel-node fetchAndFormatData/fetchAndFormatBeatMarkers.js"
},
"devDependencies": {
"#babel/cli": "^7.14.3",
"#babel/core": "^7.14.3",
"#babel/node": "^7.14.2",
"#babel/preset-env": "^7.14.4",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"css-loader": "^5.2.6",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.3.1",
"lodash.clonedeep": "^4.5.0",
"node-fetch": "^2.6.1",
"node-sass": "^6.0.0",
"sass-loader": "^11.1.1",
"style-loader": "^2.0.0",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.7.3"
},
"dependencies": {
"bezier-easing": "^2.1.0",
"howler": "^2.2.3",
"pixi.js": "^6.2.0"
}
}
Here are the original webpack config files:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/template.html')
})
],
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg|ico|pvr|mp3|fnt)$/,
type: 'asset/resource'
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
]
}
};
const { merge } = require('webpack-merge');
const common = require('./webpack.common');
module.exports = merge(common, {
mode: 'development',
devServer: {
historyApiFallback: true,
},
output: {
publicPath: '/'
},
devtool: "source-map"
});
This configuration produces a sources structure in chrome that looks like this:
localhost:8080
main.js
(index)
assets/images
animations
fonts
interface
When I updated webpack-dev-server to the latest version, 4.11.1, the assets/images folder no longer exists. I haven't be able to figure out how to get it back. Any help would be deeply appreciated.
Below is the repo, I used to load a React Application
https://github.com/kannanagasamy/react-app-without-cra
Is there a way to change the way, webpack uses ./index.js to some path like './src/index.js'?
I tried using Entry point and pointed it to './src/index.js', but it's not working and webpack is still considering index.js on root folder instead of ./src/index.js
Can somebody help me, where I am going wrong in letting webpack consider index.js inside src folder as base file.
My Current Package.Json
"scripts": {
"build": "Webpack ."
},
"devDependencies": {
"#babel/cli": "^7.18.10",
"#babel/core": "^7.19.1",
"#babel/eslint-parser": "^7.19.1",
"#babel/plugin-transform-runtime": "^7.19.1",
"#babel/preset-env": "^7.19.1",
"#babel/preset-react": "^7.18.6",
"#babel/runtime": "^7.19.0",
"babel-loader": "^8.2.5",
"eslint": "^8.23.1",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^27.0.4",
"path": "^0.12.7",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"path": "^0.12.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"#babel/cli": "^7.17.0"
}
My Current Webpack.config.file
module.exports={
mode: "development",
entry: "./index.js",
output: {
path: path.resolve(__dirname, "public"),
filename: "main.js"
},
target: "web",
resolve: {
extensions: ['.js','.jsx','.json']
},
module:{
rules: [
{
test: /\.(js|jsx)$/, //kind of file extension this rule should look for and apply in test
exclude: /node_modules/, //folder to be excluded
use: 'babel-loader' //loader which we are going to use
}
]
}
}
After updating entry point as mentioned below also, I couldn't able to move webpack to drive based on src/index.js
Codes Used
entry: path.resolve(__dirname, "src/index"),
entry: "src/index",
entry: path.resolve(__dirname, "src/index.js"),
entry: "src/index.js"
Thanks in Advance..
It seems like the issue around the command build you use which is webpack ., the option . is likely to mention the entry point at current dir ./index.js and then override the one in the configuration file so what you need to move index.js back to src/index.js and resolve the import accordingly again. Finally update the entry as you did ./src/index.js and remove . on as webpack cli.
{
build: 'webpack' // don't need to take any more extra arg
}
I'm trying to use Tailwind v2 into an old project that uses .tpl files. Not an issue as we're migrating to the world of SPAs. What I'm doing should work regardless.
I'm using the following (literally taken from my package.json):
"autoprefixer": "^10.2.5",
"babel-loader": "^8.1.0",
"css-loader": "^5.0.0",
"mini-css-extract-plugin": "^1.5.0",
"extract-text-webpack-plugin": "^3.0.2",
"postcss-loader": "^5.2.0",
"postcss-preset-env": "^6.7.0",
"webpack-merge": "^5.7.3"
"postcss": "^8.2.12",
"sass": "^1.27.0",
"sass-loader": "^10.0.3",
"style-loader": "^2.0.0",
"tailwindcss": "^2.1.1",
"webpack": "^5.35.0",
"webpack-cli": "^4.6.0"
webpack-merge is solely used to distinguish file names for production and development.
Here's an exact copy of my webpack.config.js:
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const { SRC, DIST, ASSETS } = require('./paths')
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: 'styles.css',
chunkFilename: '[id].css',
}),
new ExtractTextPlugin('styles.css', {
disable: process.env.NODE_ENV === 'development',
}),
],
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.s[ac]ss$/i,
use: ExtractTextPlugin.extract({
use: [{
loader: "css-loader"
}, {
loader: "sass-loader"
}, {
loader: "postcss-loader"
}],
// use style-loader in development
fallback: "style-loader"
})
},
],
},
entry: {
scripts: path.resolve(SRC, 'js', 'index.js')
},
output: {
// Put all the bundled stuff in your dist folder
path: DIST,
// Our single entry point from above will be named "scripts.js"
filename: '[name].js',
// The output path as seen from the domain we're visiting in the browser
publicPath: ASSETS
},
}
After running the build command, I get:
TypeError: compiler.plugin is not a function
Removing new ExtractTextPlugin from the plugin, the error is gone but another error comes up stating it's needed. I've also looked at Tailwinds' example but not having any luck. I've also looked at the ExtractTextWebpackPlugin docs but.... no luck, same error.
This project uses *.scss, *.css, *.js, *.tpl, *.php
Appreciate the help or pointers.
Thanks.
This plugin has been DEPRECATED.
Please use: https://github.com/webpack-contrib/mini-css-extract-plugin
When I run npm run build in my directory, to get all my files bundled into bundle.js, I find this error: ERROR in ./bundle.js from UglifyJs \n Unexpected token name «key», expected punc «;» [./bundle.js:8141,13].
So I went to bundle.js line 8141 and found this: for (let key in val) {
And therein lies the problem: let. Uglify cannot deal with let and const
So I've looked through the entire bundle.js file and the ONLY time let appears is literally right there, and a couple lines down, and I know specifically what package that code comes from: npm install clone-deep
None of the other packages I'm using are having this issue, they are all correctly converted from es6 before uglify runs, and I use let and const in my own code all the time. This one package only is causing me the issue.
Here's my package.json
{
"name": "jsx2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"author": "",
"license": "ISC",
"dependencies": {
"autobind-decorator": "^2.1.0",
"axios": "^0.18.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"classnames": "^2.2.5",
"clone-deep": "^4.0.1",
"prop-types": "^15.6.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-toastify": "^4.5.2",
"webpack": "^3.11.0"
},
"scripts": {
"dev": "webpack -d --watch",
"build": "webpack -p --config webpack.build.config.js"
}
}
And here's my webpack.build.config.js
// https://www.codementor.io/tamizhvendan/beginner-guide-setup-reactjs-environment-npm-babel-6-webpack-du107r9zr
var webpack = require('webpack');
var path = require('path');
var BUILD_DIR = path.resolve(__dirname, 'out/');
var APP_DIR = path.resolve(__dirname, 'src/');
var config = {
entry: ['babel-polyfill', APP_DIR + '/App.jsx'],
output: {
path: BUILD_DIR,
filename: './bundle.js'
//https://cloud.githubusercontent.com/assets/593571/20785959/290f7fbc-b7b4-11e6-9ad2-7dafd7803552.png
//https://github.com/babel/babel-loader/issues/93
},
module : {
loaders : [
{
test : /\.jsx?/,
include : APP_DIR,
loader : 'babel-loader',
options: {
"presets" : ["env", "react"],
"plugins": ["transform-decorators-legacy"]
}
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
}
};
module.exports = config;
-- edit
Just to confirm, I did actually go into clone-deep index.js and change the lets to vars, and it all worked and I got no errors. I don't really consider that as a solution, because... there's no reason why this one package should have this error and nothing else. But it is definitely this one package that is the source of the issue.
Some npm packages have no es5 version. We have to accept this or use other packages.
If you want to continue to use clone-deep, you have to add this package to include property of your babel-loader config:
...
{
test : /\.jsx?/,
include : [APP_DIR, path.resolve(__dirname, 'node_modules', 'clone-deep')],
loader : 'babel-loader',
options: {
"presets" : ["env", "react"],
"plugins": ["transform-decorators-legacy"]
}
};
...
You can read more in this issue
With my current configuration of node and webpack, I am able to run the dev-server and develop my application.
I am however unable to create the static bundle.js that i could use for a deployment on my website.
How can I configure my webpack.js files and package.json command to make it build the required bundle file ?
When I run npm build, nothing happens
When I run npm deploy, i get the following error message :
Usage: npm <command>
where <command> is one of:
access, add-user, adduser, apihelp, author, bin, bugs, c,
cache, completion, config, ddp, dedupe, deprecate, dist-tag,
dist-tags, docs, edit, explore, faq, find, find-dupes, get,
help, help-search, home, i, info, init, install, issues, la,
link, list, ll, ln, login, logout, ls, outdated, owner,
pack, ping, prefix, prune, publish, r, rb, rebuild, remove,
repo, restart, rm, root, run-script, s, se, search, set,
show, shrinkwrap, star, stars, start, stop, t, tag, team,
test, tst, un, uninstall, unlink, unpublish, unstar, up,
update, upgrade, v, verison, version, view, whoami
npm <cmd> -h quick help on <cmd>
npm -l display full usage info
npm faq commonly asked questions
npm help <term> search for help on <term>
npm help npm involved overview
Specify configs in the ini-formatted file:
C:\Users\Sébastien\.npmrc
or on the command line via: npm <command> --key value
Config info can be viewed via: npm help config
Following is my configuration :
package.json
{
"license": "UNLICENSED",
"private": true,
"version": "1.0.0",
"webPath": "web/",
"nodePath": "node_modules/",
"devDependencies": {
"autoprefixer": "^6.3.1",
"exports-loader": "^0.6.2",
"grunt": "^0.4.5",
"grunt-autoprefixer": "^3.0.3",
"grunt-contrib-concat": "^0.5.1",
"grunt-contrib-cssmin": "^0.14.0",
"grunt-contrib-less": "^1.1.0",
"grunt-contrib-uglify": "^0.11.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-css-url-rewrite": "^0.3.5",
"grunt-cssjoin": "^0.3.0",
"grunt-postcss": "^0.7.1",
"imports-loader": "^0.6.5",
"matchdep": "^1.0.0",
"redux-devtools": "^3.0.2",
"redux-devtools-dock-monitor": "^1.0.1",
"redux-devtools-log-monitor": "^1.0.4",
"webpack-shell-plugin": "^0.4.2"
},
"repository": {
"type": "git",
"url": ""
},
"dependencies": {
"babel-core": "^6.4.0",
"babel-loader": "^6.2.1",
"babel-plugin-transform-runtime": "^6.4.3",
"babel-polyfill": "^6.3.14",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-stage-0": "^6.3.13",
"babel-runtime": "^6.3.19",
"grunt-postcss": "^0.7.1",
"history": "^1.17.0",
"i18next": "^2.5.1",
"isomorphic-fetch": "^2.2.1",
"lodash": "^4.11.1",
"radium": "^0.16.2",
"rc-switch": "^1.4.2",
"react": "^0.14.6",
"react-dom": "^0.14.6",
"react-hot-loader": "^1.3.0",
"react-redux": "^4.1.2",
"react-router": "^1.0.3",
"react-router-redux": "^3.0.0",
"redux": "^3.1.6",
"redux-thunk": "^2.1.0",
"selfupdate": "^1.1.0",
"webpack": "^1.12.11",
"webpack-dev-server": "^1.14.1",
"whatwg-fetch": "^0.11.0"
},
"scripts": {
"start": "node webpack.dev-server.js",
"build": "webpack",
"deploy": "NODE_ENV=production webpack -p --config webpack.production.config.js"
}
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
var node_modules_dir = path.join(__dirname, 'node_modules');
var devFlagPlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});
console.log(__dirname);
var config = {
entry: [
'babel-polyfill',
'webpack-dev-server/client?http://127.0.0.1:3000',
'webpack/hot/only-dev-server',
'./app/Resources/react/app.js'
],
output: {
path: path.join(__dirname, 'web/js'),
filename: 'bundle.js',
publicPath: 'http://127.0.0.1:3000/static/'
},
debug: true,
devtool: 'eval',
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
devFlagPlugin
],
module: {
loaders: [
{
loaders: ["react-hot","babel-loader?plugins=transform-runtime&presets[]=es2015&presets[]=stage-0&presets[]=react"],
test: /\.js$/,
include: path.join(__dirname, 'app/Resources/react')
}
]
}
};
module.exports = config;
/*
new webpack.ProvidePlugin({
'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
})
*/
webpack.dev-server.js
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
quiet: false,
noInfo: false,
contentBase: "./assets"
}).listen(3000, 'localhost', function (err, result) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:3000');
});
webpack.production.config.js
var path = require('path');
var node_modules_dir = path.resolve(__dirname, 'node_modules');
var config = {
entry: [
'babel-polyfill',
'./app/Resources/react/app.js'
],
output: {
path: path.join(__dirname, 'web/js'),
filename: 'bundle.js'
},
module: {
loaders: [
{
loaders: ["babel-loader?plugins=transform-runtime&presets[]=es2015&presets[]=stage-0&presets[]=react"],
test: /\.js$/,
include: path.join(__dirname, 'src/react')
}
]
}
};
module.exports = config;
you missed run
npm run deploy
run is required for all scripts. To help with common tasks npm knows how to use several preconfigured scripts such as start and test which is why npm start is an equivalent of npm run start.