Webpack doesn't run clean when watch is set to true - javascript

This is my webpack.config.js file:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {
entry: {
bundle: './javascript/index.js'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
use: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(jpe?g|png|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 40000
}
},
'image-webpack-loader'
]
}
]
},
plugins: [
new ExtractTextPlugin('style.css'),
new HtmlWebpackPlugin({
template: 'src/index.html'
})
],
watch: true
};
module.exports = config;
As you can tell from the last line I'm setting the watch option to true. In addition, I'm using chunkhash to generates a new javascript file when I make a change to any of my javascript files. However, it is not running my rinraf clean command when the watch option is set to 'true'.
Here is a portion of my package.json file that:
{
"name": "budgety",
"version": "1.0.0",
"description": "Budget app",
"main": "app.js",
"scripts": {
"clean": "rimraf build",
"build": "npm run clean && webpack"
},
.
.
.
Why is this happening?
My goal is to:
Have my compiled javascript be updated after I update any of my javascript files, so I don't need to run 'npm run build' every single time I make a change to my js files.
Clean the old javascript 'hashed' file which used be taken care of by 'rimraf' but for some reason it isn't cleaning the new hashed javascript files in watch mode.

The watch mode works in a way that it only recompiles the files that were changed. That's why, normally, during the watch mode the hash prefixes are not enabled (because the files are changed nearly every minute which makes it more complicated to track the changed hashes etc). In other words one should have a dev and prod environments that will behave slightly differently.
E.g. you need to pass an argument, see here how and then use them in your config file:
filename: env.withHashPrefixes ? '[name].[chunkhash].js' : '[name].js'
Now you will not need to clean anything because the filenames are always the same
Original answer
It does and it will not run your rimraf command because the watch happens inside of the webpack ind it has no idea what you did run outside of it.
Use clean-webpack-plugin which is as easy as
plugins: [
new CleanWebpackPlugin('build')
]

I've experienced the same problem that my assets in /assets/ folder were cleaned and not rebuilt when enabling output.clean.
I've worked around this by ignoring /assets/ from cleaning in webpack.config.js. However, it's not the perfect solution as obsolete assets would remain in the folder.
output: {
clean: {
keep: /assets\//,
},
},

Related

Electron-Typescript: Bundling everything

I'm trying to create a web app using electron written in Typescript. I'm having problems when building my application. Specifically, I am not sure on how to combine: tsc (To convert my .ts file to .js) and then electron dist/main.js. Potentially, I want to run npm start which first compiles my .ts file and then run electron. Can anyone comment on what would be the best approach to achieve this?
Use ts-loader with webpack to bundle .ts files with config like below,
const path = require("path")
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
and then in your npm script include these,
{
"build-watch": "webpack -w",
"electron": "electon dist/main.js"
}
then start both using npm-run-all (or any other tool like concurrently),
npm-run-all start build-watch electron
I would suggest using https://webpack.electron.build/. It has instructions for adding typescript support here https://webpack.electron.build/add-ons#typescript

react-dom blowing out webpack bundle size MASSIVELY

This has got to be one of the strangest issues with webpack i have ever come across...
Check out this bundle breakdown:
react 116.01KB - fair enough
react-dom 533.24KB - seriously WTF
I thought it may be a corruption in my dependencies but nuking node_modules and reinstalling doesn't have any effect. I guess it's something to do with the way webpack is bundling it but i'm lost for ideas. The way i'm handing .js imports is pretty stock standard.
// webpack.config.js
const path = require('path');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const Dashboard = require('webpack-dashboard');
const DashboardPlugin = require('webpack-dashboard/plugin');
const dashboard = new Dashboard();
module.exports = {
context: path.join(__dirname, 'src'),
entry: {
bundle: './index.js',
},
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'build'),
},
module: {
rules: [
{
test: /\.html$/,
use: 'file-loader?name=[name].[ext]',
},
{
test: /.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'postcss-loader',
],
}),
},
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
],
},
plugins: [
// new BundleAnalyzerPlugin(),
new ExtractTextPlugin('styles.css'),
new DashboardPlugin(dashboard.setData),
],
devServer: {
quiet: true,
},
};
// .babelrc
{
"presets": [
"react",
"es2015"
],
"plugins": ["transform-object-rest-spread"]
}
http://elijahmanor.com/react-file-size/
In v15.4.0 the file size of react-dom grew from 1.17kB to 619.05kB. Which means my webpack setup isn't doing anything wrong bundling files. The reason why this module grew so large is because code was transferred from the react module.
I had to change my webpack.config.js, from
devtool: 'inline-source-map'
to
devtool: 'source-map'
Now it generates a much smaller .js + a separate .js.map file, for each of the chunks.
Notice the JS size is even less than react-dom.production.min.js in node_modules:
If you look into the corresponding folders under the node_modules folder, and note the file sizes, you'll see that there's nothing to be surprised about:
That is, the size of the bundle grows noticeably because the size of react-dom.js is large.
Add this following commands at plugins to minify your imports:
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin(GLOBALS),
new webpack.optimize.UglifyJsPlugin(),
You should create a file or option to production bundle to use this plugins

How to disable AMD on 4 files and load them in order with webpack

I need to disable AMD on 4 files and load video.js first before loading the other 3 files, because they depend on it. When I tried doing it in webpack.config.js like so:
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: __dirname + '/public',
filename: 'bundle.js'
},
devServer: {
inline: true,
contentBase: './src',
port: 3333
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
})
],
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules|lib/,
loader: 'babel',
query: {
presets: ['es2015', 'react', 'stage-2'],
plugins: ['transform-class-properties']
}
},
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /[\/\\]lib[\/\\](video|playlist|vpaid|overlay)\.js$/,
exclude: /node_modules|src/
loader: 'imports?define=>false'
}
]
}
}
It doesn't really work, because it just loads video.js (with disabled AMD) and completely ignores the other 3 files.
My folder structure is like so:
▾ lib/
overlay.js
playlist.js
video.js
vpaid.js
▸ node_modules/
▾ public/
200.html
bundle.js
▾ src/
App.js
index.html
main.js
LICENSE
package.json
README.md
webpack.config.js
Now, I found something that takes me 1 step back, because now even video.js doesn't load:
require('imports?define=>false!../lib/video.js')
require('imports?define=>false!../lib/playlist.js')
require('imports?define=>false!../lib/vpaid.js')
require('imports?define=>false!../lib/overlay.js')
and instead just throws these kinds of warnings:
WARNING in ./~/imports-loader?define=>false!./lib/video.js
Critical dependencies:
15:415-422 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
# ./~/imports-loader?define=>false!./lib/video.js 15:415-422
WARNING in ./~/imports-loader?define=>false!./lib/playlist.js
Critical dependencies:
10:417-424 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
# ./~/imports-loader?define=>false!./lib/playlist.js 10:417-424
WARNING in ./~/imports-loader?define=>false!./lib/vpaid.js
Critical dependencies:
4:113-120 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
# ./~/imports-loader?define=>false!./lib/vpaid.js 4:113-120
WARNING in ./~/imports-loader?define=>false!./lib/overlay.js
Critical dependencies:
10:416-423 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
# ./~/imports-loader?define=>false!./lib/overlay.js 10:416-423
So, my question is, how can I make this work in webpack.config.js so that I don't get these warnings?
I have solved the problem! To make this work you need this:
{
test: /[\/\\]lib[\/\\](video|playlist|vpaid|overlay)\.js$/,
exclude: /node_modules|src/
loader: 'imports?define=>false'
}
and this
require('script-loader!../lib/video.js')
require('script-loader!../lib/playlist.js')
require('script-loader!../lib/vpaid.js')
require('script-loader!../lib/overlay.js')
together!
Now, if you use this (instead of script-loader):
require('imports?define=>false!../lib/video.js')
require('imports?define=>false!../lib/playlist.js')
require('imports?define=>false!../lib/vpaid.js')
require('imports?define=>false!../lib/overlay.js')
It's not gonna work! (you need both imports-loader and script-loader working in unison.

Webpack - [HMR] Hot Module Replacement is disabled

I've looked around, but can't get any of the answers I've seen on stackoverflow to work.
I cannot use the command line for webpack or the webpack dev-server; I am restricted to using the Node API.
Below is how I am using webpack.
webpack.config.js
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:3000',
// i've also tried webpack/hot/dev-server here
'webpack/hot/only-dev-server',
path.join(__dirname, 'src', 'js', 'app.jsx')
],
output: {
path: path.join(__dirname, 'dist', 'js'),
filename: 'script.js',
publicPath: '/dist/'
},
module: {
loaders: [{
test: /\.(js|jsx)$/,
loaders: ['react-hot', 'babel']
}]
},
plugins: []
};
contained in a gulp task "start"
gulp.task('start', function (callback) {
var config = Object.create(require('webpack.config.js'));
config.plugins.push(new webpack.HotModuleReplacementPlugin());
var devServer = new webpackDevServer(webpack(config), {
stats: { colors: true },
contentBase: path.resolve(__dirname, 'dist'),
progress: true,
inline: true,
hot: true
});
});
What I expect
When I run gulp start, I expect the webpack dev server to spin up, allowing me to hit localhost:3000/. This should load an index.html from my project's /dist/ folder. So far so good. I expect that when I make a change to a file (e.g., app.jsx), that the change would be present.
What is actually happening
I am getting the error "[HMR] Hot Module Replacement is disabled", with no further explanation.
Any help would be appreciated. I have been trying to get hot reloading working for a full day.
in your webpack.config.js on the plugins section try this,
plugins: [new webpack.HotModuleReplacementPlugin()]
I know you are pushing the plugin in your gulp task but you have to use --hot --inline on cli or on your npm script
Try to run webpack as
webpack-dev-server --hot --inline in packge.json,
somehow official docs is wrong now.

How to load library source maps using webpack?

I'm building two projects with webpack; one is a library for the other.
Is it possible to consume the sourcemaps from my library project when building my wrapper project? I would like the ability to debug my library code from my wrapper UI.
My build works correctly in that the library is built in. The only issue is sourcemaps. The JavaScript I see in the browser debugger is uglified, because sourcemaps are unavailable.
Snippet of my project structure:
+-- my-ui/
+-- dist/
+-- my-ui.js
+-- my-ui.js.map
+-- node_modules/
+-- my-lib/
+-- dist/
+-- bundle.js
+-- bundle.js.map
Snippet from webpack.config.js:
module.exports = {
entry: './src/js/main.jsx',
output: {
path: path.join(__dirname, 'dist'),
filename: 'my-ui.js',
library: 'my-ui',
libraryTarget: 'umd'
},
devtool: 'source-map',
module: {
loaders: [
{test: /\.jsx?$/, loader: 'babel', include: path.join(__dirname, 'src')}
]
},
plugins: [
new Clean('dist'),
new HtmlWebpackPlugin({
template: 'src/index.html',
inject: true
})
]
};
I finally figured out my issue...
Thanks to #BinaryMuse for the tip on source-map-loader. This indeed was the right way to go, though it wasn't working for me initially.
What I eventually realized is that I need to enable the source-map-loader for webpack in both "my-lib" and "my-ui". Without source-map-loader in "my-lib" webpack config, the source-map-loader inside "my-ui" errors (with a warning message sadly) because it cannot locate source maps for transitive dependencies of "my-lib". Apparently the source maps are so good that source-map-loader is able to peek at all aspects of the dependency tree.
Also of note, I ran into an issue using source-map-loader in conjunction with react-hot-loader. See, react-hot-loader does not include source maps. When source-map-loader tries to find them (because it's just scanning everything), it cannot and aborts everything.
Ultimately, I'd like source-map-loader to be more fault tolerant, but when set up correctly, it does work!
devtool: 'source-map',
module: {
preLoaders: [
{test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/},
{test: /\.jsx?$/, loader: 'source-map', exclude: /react-hot-loader/}
],
loaders: [
{test: /\.jsx?$/, loader: 'raect-hot!babel', exclude: /node_modules/}
]
}
My answer is similar to #Jeff Fairley's and I had the same directory structure, with the only difference being that I was using module: { rules: [] } instead of his module: { preLoaders: [..], loaders: [...]}. This is what I had to add to my webpack.config.js file:
mode: 'development',
devtool: 'eval-source-map',
module: {
rules: [
{
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
}
]
},
Then I ran
npm i -D source-map-loader
and I saw the TypeScript source code of the dependency I was using when clicking through tracebacks in Chrome's devtools. See the Webpack docs for source-map-loader.
I am using create-react-app and this is how I Fixed it (without running eject cmd)
Note : If your app is already overriding webpack config using react-app-rewired you can ignore first three steps.
npm i react-app-rewired -D - This will help you to override webpack
configuration.
package.json - change your scripts, replace react-scripts with react-app-rewired
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}
config-overrides.js - create this file in the parent level of the app.
npm i source-map-loader -D - To load source maps (assuming that your lib's dist has source map file). It doesn't matter which build tool(ex: Rollup, webpack or parcel) you use to generate sourcemap.
Copy below code in config-overrides.js
module.exports = {
webpack: (config, env) => {
// Load source maps in dev mode
if (env === 'development') {
config.module.rules.push({
test: /\.(js|mjs|jsx|ts|tsx)$/,
use: ['source-map-loader'],
enforce: 'pre',
});
// For `babel-loader` make sure that sourceMap is true.
config.module.rules = config.module.rules.map(rule => {
// `create-react-app` uses `babel-loader` in oneOf
if (rule.oneOf) {
rule.oneOf.map(oneOfRule => {
if (
oneOfRule.loader &&
oneOfRule.loader.indexOf('babel-loader') !== -1
) {
if (oneOfRule.hasOwnProperty('options')) {
if (oneOfRule.options.hasOwnProperty('sourceMaps')) {
// eslint-disable-next-line no-param-reassign
oneOfRule.options.sourceMaps = true;
}
}
}
});
}
return rule;
});
}
return config;
},
};
Restart your app (if it's already running). source files get loaded in different locations, based on path in map file. Check all folders patiently :)
Note :
1. Your source maps get loaded in one of the folder(ex : localhost:3000 or webpack:/// ) based on path it reads from xxx.js.map file.
2. If you are using rollup for your libs, please make sure you give proper path in the configuration file (output.sourcemapPathTransform ), This will help to load sourcemaps in the proper location.
You should be able to use any of the eval source map options that Webpack provides.
Really that just amounts to setting the right devtool option in your webpack.config.js for the my-lib project.
devtool: 'eval',
eval and eval-source-map should both work.
See the Webpack documentation for the various options.

Categories