I'm trying to build my React project with Webpack using hot module replacement. But, Webpack ignores file changes. What am I doing wrong?
My config:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:4567',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: [path.join(__dirname, 'src')]
}]
}
};
My files structure:
src
--app
----actions
----components
----constants
----reducers
----app.js
----config.js
--index.js
Hot module replacement works fine if module file is in "src" folder, otherwise nothing happens on changes.
Thanks!
Because you've set include in your webpack config.
You can change your config like this:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:4567',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: [`all of your dirs you want to watch`]
}]
}
};
Related
I know this question has been asked before, but I honestly can't find the answer anywhere-- it appears as if I'm doing everything I should however bundle is not created. So I have this webpack.config.js file that's supposed to handle HMR + React, and typescript (with tsx syntax), but it's not creating the bundle. Throws no errors on compilation, and seems to be doing alright, but the bundle returns a 404 when I try to fetch it. Here's my file structure:
someApp/
src/
index.tsx
components/
Hello.tsx
dist/
webpack.config.js
...
And here's my webpack config:
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/index.tsx'
],
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/public/'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devtool: 'eval',
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js']
},
module: {
loaders: [
{
test: /\.tsx?$/,
loaders: [
'react-hot-loader',
'ts-loader'
],
include: path.join(__dirname, '/src')
}
],
preLoaders: [
{ test: /\.js$/, loader: 'source-map-loader' }
]
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
};
Another strange thing is that I think it might have something to do with executing this through node, since when I just run webpack by itself it compiles the bundle. Here's my code for starting up the server:
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
}).listen(3000, 'localhost', function (err, result) {
if (err) {
return console.log(err)
}
console.log('Listening at http://localhost:3000/')
})
Maybe I'm missing something, but I'm pretty new to webpack so any help would be amazing!
Thats because webpack-dev-server is serving bundle.js from memory. This is done to make serving bundle.js fast. You can add another webpack config for production that spits out bundle.js to disk
module.exports = {
entry: './src/index.tsx',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/public/'
},
.
.
.
and all your other modules, just don't include your dev-server
if you want to fetch bundle.js like localhost:3000//..../bundle.js
try this
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry:'./src/index.tsx',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/public/'
},
//plugins: [
// new webpack.HotModuleReplacementPlugin()
//],
devtool: 'eval',
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js']
},
module: {
loaders: [
{
test: /\.tsx?$/,
loaders: [
'react-hot-loader',
'ts-loader'
],
include: path.join(__dirname, 'src')
}
],
preLoaders: [
{ test: /\.js$/, loader: 'source-map-loader' }
]
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
};
EDIT: If you want to fetch bundle.js
you have to use what is defined in the publicPath: '/public/'. so for you the url you can fetch bundle.js from is this localhost:3000/public/bundle.js
I think you need to change your output to this:
output: {
path: path.join(__dirname, '/dist'), // <- change last argument
filename: 'bundle.js',
publicPath: '/public/'
},
For debug purposes, I would like to get the line number which produced the error but I am getting this:
It is referencing bundle.js though I've specified debug=true in the webpack.config.js:
var path = require('path')
var webpack = require('webpack')
module.exports = {
debug: true,
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'./index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin()
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['babel'],
exclude: /node_modules/,
include: __dirname
}]
}
}
Anyway I can get the line number in the pre-compiled js?
I've tried adding pathInfo as this answer recommended but to no avail.
This is my webpack.config.js file:
const webpack = require('webpack');
const path = require('path');
module.exports = {
cache: true,
devtool: 'source-map',
entry: {
app : [
'./src/index.js'
],
vendor: ['lodash']
},
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist'),
publicPath: '/dist/',
pathinfo: true
},
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loaders: ['babel'] },
{ test: /\.scss/, exclude: /node_modules/, loaders: ['style', 'css', 'sass'] }
]
},
plugins: [
new webpack.NoErrorsPlugin(),
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js', Infinity)
]
};
And this is my scripts that runs the webpack-dev-server:
const webpack =require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const webpackConfig = require('../webpack.config');
const _ = require('lodash');
const webpackDevConfig = _.cloneDeep(webpackConfig);
const devPort = 3000;
webpackDevConfig.entry.app.unshift('webpack/hot/dev-server');
webpackDevConfig.entry.app.unshift('webpack-dev-server/client?http://localhost:' + devPort + '/');
webpackDevConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
new WebpackDevServer(webpack(webpackDevConfig), {
publicPath: webpackConfig.output.publicPath,
hot: true,
stats: {
colors: true,
chunks: false
}
}).listen(devPort, 'localhost');
The webpack command output is good (bundle.js and vendor.bundle.js), however, the dev server fails with webpackJsonp is not defined (although its in-memory compilation succeeded).
When removing CommonsChunkPlugin from webpack.config.js - it all works fine:
...
entry: [
'./src/index.js'
],
...
plugins: [
new webpack.NoErrorsPlugin()
]
Any ideas?
In your index.html file just call vendor.bundle.js before bundle.js
<script src="assets/js/vendor.bundle.js"></script>
<script src="assets/js/bundle.js"></script>
That's all, now it should work. More information.
Rename vendor entry point to
'vendor.js': ['lodash']
Just to expand a little on the concept, the vendor has to come first since the runtime is contained in there (everything that defines all the variables and methods run during client load time because of all the webpacking).
If you use a manifest file (because of chunking and so on), you'll have to put that first since it will then contain the runtime because of the way the module is built.
By default Webpack looks for a specific index.html file in a specified directory, right? What I want to know is can I tell webpack to look for and inject my bundled files in a file that I specify?
I ask this because I'm trying to develop a Ghost theme with webpack and by default, a Ghost theme looks for a default.hbs file to serve as an index file.
I tried to use the HtmlWebpackPlugin to set the filename for entry all while making the same file for web pack's output, but it's not working.
This is my current webpack.dev.config.js:
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:2368',
'webpack/hot/only-dev-server',
'./src/router'
],
devtool: 'eval',
debug: true,
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
publicPath: '/static/'
},
resolveLoader: {
modulesDirectories: ['node_modules']
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new HtmlWebpackPlugin({
hash: true,
filename: 'default.hbs',
template: __dirname + '/public/default.hbs',
})
],
resolve: {
extensions: ['', '.js', '.sass', '.css', '.hbs']
},
module: {
loaders: [
// js
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel'],
include: path.join(__dirname, 'src')
},
// CSS
{
test: /\.sass$/,
include: path.join(__dirname, 'src'),
loader: 'style-loader!css-loader!sass-loader'
},
// handlebars
{
test: /\.hbs$/,
include: path.join(__dirname, 'public'),
loader: 'handlebars-template-loader'
}
]
},
node: {
fs: 'empty'
}
};
Easiest way: you can configure webpack to use any file and template file via the html-webpack-plugin plugin. You can also specify the element to inject into.
import HtmlWebpackPlugin from 'html-webpack-plugin';
[...]
const plugins = [
new HtmlWebpackPlugin({
template: 'templates/myTemplateFile.tpl.html',
inject: 'body',
filename: 'myOutputFile.html'
})
];
I've got a React/Redux app and I'm using webpack to transpile my JSX and ES6 and load my stylesheets and images into my JS. My dev server is hosted on port 3000.
Here's my webpack.config.js:
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'./src/js'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new HtmlWebpackPlugin({
favicon: 'src/images/favicon.ico'
})
],
module: {
loaders: [{
test: /\.js$/,
loaders: [ 'babel' ],
exclude: /node_modules/,
include: __dirname
}, {
test: /\.less?$/,
loaders: [ 'style', 'css', 'less' ],
include: __dirname
},
{
test: /\.(otf|eot|svg|ttf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loaders: [ 'url' ],
include: __dirname
},
{
test: /\.(png|ico|gif)?$/,
loaders: [ 'file' ],
include: __dirname
}]
}
};
When I hit localhost:3000, everything that I would expect to be there is there, except my favicon. If I go to localhost:3000/static/favicon.ico, my favicon is there. Could use some expertise debugging this issue.
The browser will look for your favicon in localhost:3000/favicon.ico, so that's where it needs to be. Try rewriting the url to serve favicon.ico for the /favicon.ico route. For example, if you're using historyApiFallback, do:
historyApiFallback: {
rewrites: [
// shows favicon
{ from: /favicon.ico/, to: '[path/to/favicon]' }
]
}