Webpack - browser refresh on a file change which isn't module - javascript

I want to refresh page when I change (save) ./src/*.js files in my code editor.
The problem is I'm not importing this files in my entry point (with import in index.js) but I'm joining them with a plugin so code is in browser's global scope rather then in module.
Basically I want to split longer JavaScript code into smaller files, I don't want to have modules.
I've tried many configurations and closest to my needs is that below, except that it doesn't refresh browser, (it recompiles).
How can I achieve recompile and refresh on JavaScript which should be in globalscope of the browser (or all code in one module)?
webpack.config.js:
const path = require('path');
const MergeIntoSingleFilePlugin = require('webpack-merge-and-include-globally');
const FileWatcherPlugin = require("file-watcher-webpack-plugin");
module.exports = {
context: __dirname,
entry: { bundle: './src/index.js' },
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}]
},
plugins: [
new MergeIntoSingleFilePlugin({
files: {
"app.js": [
path.resolve(__dirname, './src/setup.js'),
path.resolve(__dirname, './src/buttons.js'),
path.resolve(__dirname, './src/circle.js'),
path.resolve(__dirname, './src/wall.js')
]
}
}),
new FileWatcherPlugin({
root: __dirname,
files: ['*.js']
})
],
devServer: {
contentBase: './dist',
watchOptions: {
aggregateTimeout: 300,
poll: 1000
},
hot: true,
inline: true,
// publicPath: "./src",
watchOptions: {
ignored: './node_modules/'
}
}
};
npm start:
webpack-dev-server --open --inline --hot --watch --progress
and the setup.js, buttons.js etc are regular JS script files, not exported classes.
Any ideas appreciated!

Related

webpack-dev-server refuses to hot-reload html file

When using webpack-dev-server, when I make changes to the javascript file the changes are immediately reflected on the webpage.
However, when I make a change to the HTML file, the website does not reflect them. In order to see the new html page, I must first run webpack --mode production, and then, if I re-run webpack-dev-server --hot --mode development, I can see the new HTML changes.
This is quite annoying and I'd like my html changes to be hot-reloaded just like the javascript code. Is there a trick I'm missing? I've spent all day googling and playing with options. The only thing that has helped is to add
devServer:
...
devMiddleware: {
writeToDisk: true
},
to my webpack.config.js as per this answer. However, this has the following problem: My output dist/ folder gets clogged with .js files with checksum names every time a hot reload happens, which is also really annoying.
My project tree:
The full webpack.config.js:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: './src/index.ts',
watch: true,
module: {
rules: [
{
test: /\.ts?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/'
},
plugins: [
new HtmlWebpackPlugin({
title: "My app",
template: "./src/index.html",
/* This output directory is relative to the **OUTPUT** 'publicPath'!
So, if you were to write "./dist/index.html" below, it would output it in "./dist/dist/index.html"!
(You can verify this by running `npx webpack --watch` and looking what files it touches/generates.)
*/
filename: "index.html",
inject: "body"
})
],
devServer: {
// devMiddleware: { writeToDisk: true },
static: {
directory: path.join(__dirname, "dist"),
watch: true
},
compress: true,
webSocketServer: 'ws',
host: '0.0.0.0',
port: 10000,
/* Ensure I can access the server directly, without incurring the 'invalid host header' error */
allowedHosts: "all",
/* So that the webpack-dev-server reloads when I change the index.html file, even though it isn't explicitly listed anywhere. */
watchFiles: ['src/**/*'],
open: true,
hot: true,
},
};
Nevermind, I have found the issue:
Unfortunately Stackoverflow doesn't support line numbers, but if you look in the webpack.config.js code in my original question, you will find the following code:
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/'
},
That publicPath parameter appears to be what was causing the problem. Removing it made the hot-reload 'magic' autodetect that I've changed the HTML file, and re-deploy it.

webpack 5 does not accept any setting for devtool

When building with webpack 5, I get the error:
[webpack-cli] 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.
In my webpack.config.js however, I have the setting:
devtool: 'eval-cheap-source-map',
Ive also tried eval as value which also does not work, although this website (https://webpack.js.org/configuration/devtool/) seems to indicate that it should.
I do not understand, what is going wrong here?
edit:
my webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
plugins: [
new HtmlWebpackPlugin({
title: 'MyApp',
}),
],
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'var',
library: 'MyApp'
},
resolve:{
alias:{
EVENTS: path.resolve(__dirname, "src/events"),
MODELS: path.resolve(__dirname, "src/models"),
GUI: path.resolve(__dirname, "src/gui"),
HELPER: path.resolve(__dirname, "src/helper")
}
},
devtool: 'eval-cheap-source-map',
devServer: {
watchContentBase: true,
contentBase: path.resolve(__dirname, 'dist'),
port: 9000
},
module: {
rules: [
{
test:/\.css$/,
use:['style-loader', 'css-loader']
}
]
},
}
my buildscript is webpack src/app.js -d --watch
Remove the -d parameter from your build script. -d stands for devtool, but it is not followed by a parameter value in your command.

How to run unit test with webpack?

I have a Node Js server that I bundled with webpack with the following config:
module.exports = {
entry: './build/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
devtoolModuleFilenameTemplate: '../[resource-path]',
},
target: 'node',
node: {
__dirname: true,
},
externals: {
kcors: 'kcors',
'koa-bodyparser': 'koa-bodyparser'
},
module: {
rules: [
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre"
},
],
},
resolve: {
extensions: ['.js'],
},
// plugins: [
// new webpack.DefinePlugin({
// "process.env": JSON.stringify(dotenv.parsed)
// }),
// ],
devtool: 'eval-source-map'
};
This created a single file main.js inside dist
Everything looks good so far. I manually tested the server and it works.
Now, before I used webpack, I have a set of unit tests that I named with the .spec.js suffix inside my entry folder (the build/ folder) and each .js file has each own .spec file sibling located in the same directory of the .js.
To run theses unit test, I used mocha with the command: mocha build/**/*.spec.js --recursive --timeout 20000
Since I am new to webpack and the concept of bundling, how do I run the same tests from the main.js file ? I want to make sure that all tests are still passing in the bundled file
use
npm install mocha mocha-loader
config your webpack.config.js file like:
module.exports = {
entry: './entry.js',
output: {
path: __dirname,
filename: 'bundle.js',
},
module: {
rules: [
{
test: /test\.js$/,
use: 'mocha-loader',
exclude: /node_modules/,
},
],
},
};
then, call your test file from your main file like:
(into app.js)
import test from 'allMyTests';

How can Vue js load image from /dist/ folder when it does not exist?

So I'm trying to learn Vue.js + webpack and initated a project by following these steps:
f:www\> npm install -g vue-cli
f:www\> vue init webpack-simple my-project
f:www\> cd my-project
f:www\> npm install
f:www\> npm run dev
The default page runs on http://localhost:8080/.
Now, in webpack.config.jsfile I have the following lines:
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'main.js'
},
and in the index.html we find the following line <script src="/dist/main.js"></script>
At this point I thought Webpack was a bit like Gulp in that it compiles src files and puts them in the /dist/ folder.
But Webpack never creates the /dist/ folder.
How can the Vue logo be loaded from <img src="/dist/logo.png?82b9c7a5a3f405032b1db71a25f67021"> when /dist/ folder does not exist?
Why is main.js not created?
webpack.config.js (short version)
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'main.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
};
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map';
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
So after some more googling, I found this turorial that explains the entire webpack-simple setup.
Here is the section regarding the /dist/ folder:
npm run build
Right now we are simply using npm run dev to work with and test out an
installation of the Vue Cli tool. This is great
for testing in the local environment, but what about if you actually
want to publish your application to the web? In this case you will
instead run npm run build. This will build your application for
production and you’ll see a new /dist/ folder which contains the
finished bundle.
So during development, the files are placed in a chached / temp location (not sure where)

Getting "Aborted because 0 is not accepted" and full page reload with react-hot-loader

I am trying to set up webpack hot reloading with react-hot-loader. It mostly seems to be working. I am using webpack in an existing rails app.
But it isn't hot-reloading. It is simply triggering a reload every time my react code is changed. The error messages I get are:
[HMR] Cannot apply update. Need to do a full reload! - dev-server.js:18
[HMR] Error: Aborted because 0 is not accepted - dev-server.js:19
at hotApply (http://localhost:8080/assets/webpack/bundle.js?body=1:380:31)
at hotUpdateDownloaded (http://localhost:8080/assets/webpack/bundle.js?body=1:293:13)
at hotAddUpdateChunk (http://localhost:8080/assets/webpack/bundle.js?body=1:273:13)
at webpackHotUpdateCallback (http://localhost:8080/assets/webpack/bundle.js?body=1:5:12)
at http://localhost:8080/assets/webpack0.bd89931b2fa8e2901794.hot-update.js:1:1
Navigated to http://lvh.me:3000/react_page
Here is my webpack.hot.config.js settings:
var path = require('path');
var webpack = require('webpack');
var config = module.exports = {
// Set 'context' for Rails Asset Pipeline
context: __dirname,
entry: {
App: [
'webpack-dev-server/client?http://localhost:8080/', // WebpackDevServer host and port
'webpack/hot/only-dev-server', // "only" prevents reload on syntax errors
'./app/frontend/javascripts/app.js' // Your appʼs entry point
],
vendor: ['jquery', 'react', 'react-dom', 'react-redux', 'redux','redux-thunk']
},
devtool: 'inline-source-map',
// Require the webpack and react-hot-loader plugins
plugins: [
//new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.CommonsChunkPlugin(
{
name: 'vendor',
chunks: [''],
filename: 'vendor.js',
minChunks: Infinity
}),
new webpack.NoErrorsPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jquery': 'jquery'
})
],
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: [
'react-hot',
'babel?presets[]=es2015&presets[]=react'
],
cacheDirectory: true
}
]
},
output: {
path: path.join(__dirname, 'app', 'assets', 'javascripts', 'webpack'), // Save to Rails Asset Pipeline
filename: 'bundle.js', // Will output App_wp_bundle.js
publicPath: 'http://localhost:8080/assets/webpack',
//publicPath: 'http://localhost:8080/assets/webpack' // Required for webpack-dev-server
},
resolve: {
extensions: ['', '.js', '.jsx'],
modulesDirectories: ['node_modules'],
},
};
And I run the code with
webpack-dev-server -d --config webpack.hot.config.js --hot --inline
The rails development environment serves the webpack files outside the application asset pipeline via the webpack-dev-server because of the following setting in my development.rb file.
config.action_controller.asset_host = Proc.new { |source|
if source =~ /webpack\/bundle\.js$/i
"http://localhost:8080"
end
}
I have been trying to get this working for hours. Any help would be appreciated.
Thanks guys!
Ok i was getting the same error, but after trying some things out i figured this out: My root component was a stateless functional component (pure function). I refactored it to a class component and BAM! the hot reloading is working again.
Before:
const App = (props) => (
<div>
<Header links={headerLinks} logoSrc={logoSrc} />
{props.children}
</div>
);
After:
class App extends React.Component {
render() {
return (
<div>
<Header links={headerLinks} logoSrc={logoSrc} />
{this.props.children}
</div>
);
}
}
As the answers provided above are still not working on my side with webpack 5,
Here is the working config from webpack
In webpack.config.js
devServer: {
.
.
.
hot: true,
}
In the webpack entrypoint index.js add
if (module.hot) {
module.hot.accept();
}
In package.json start script
"scripts": {
.
.
"start": "webpack serve --config /webpack.config.js"
},
I recently ran into this exact issue, the fix for me was removing this from the entries array: 'webpack-dev-server/client?http://localhost:9000/',.
As I was also running --hot as a command line argument, there were two instances of webpack-dev-server getting into a bad state.
I don't know if this will specifically help your issue, but I encountered this error recently as well - i fixed it by adding a .js extension to the module I was trying to set up with hmr - here was my code
if (module.hot) {
module.hot.accept('app/Routes', () => (
getRoutes = require('app/Routes')
))
}
I updated it to getRoutes = require('app/Routes.js') and the error disappeared, using webpack ^2.0.0-beta.
it also works if i add the JS extension as the first argument of hot accept like so:
if (module.hot) {
module.hot.accept('app/Routes.js', () => (
getRoutes = require('app/Routes')
))
}
so now it matches whats on the webpack HMR page
I ran into a similar problem.
After 2 days of research and trying different things, I found out the simplest cause to my problem ever:
in webpack.config.js, I had a HRM dev server enabled. And I also had a HMR server run from command line. Thanks to hint from Tyler Kelley (see above), just by removing --hot from command line, it works OK now.
current webpack.config.js
devtool: "inline-source-map",
devServer: {
publicPath: '/dist/',
contentBase: path.join(__dirname, 'public'),
port: 9000,
hot: true
},
With this configuration, don't do this:
npx webpack-dev-server --hot --inline
Do this:
npx webpack-dev-server
For "webpack": "^5.74.0" and "webpack-dev-server": "^4.11.1".
I set devServer.static = ['./webpack-dev-server', './dist'], in webpack.config.js.
There is my config:
module.exports = {
devtool: 'inline-source-map',
devServer: {
open: true,
static: ['./webpack-dev-server', './dist']
},
entry: path.join(__dirname, 'src', 'index.ts'),
module: {
rules: [
{
test: /\.(ttf|png|svg|jpg|jpeg)$/i,
type: 'asset/resource',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: path.join(__dirname, 'tsconfig.json')
}
}
]
},
mode: 'development',
output: {
filename: '[name][contenthash].js',
path: path.join(__dirname, 'dist'),
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src', 'index.html'),
inject: 'body'
})
],
resolve: {
extensions: ['.js', '.ts']
}
}

Categories

Resources