webpack-dev-server not serving index.html generated by HtmlWebPackPlugin - javascript

I have the following webpack.config.js
const path = require("path");
const webpack = require("webpack");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
entry: "./src/index.js",
mode: "development",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
resolve: { extensions: ["*", ".js"] },
output: {
path: path.resolve(__dirname, "public/dist/"),
publicPath: "/dist/",
filename: "bundle.js"
},
devServer: {
contentBase: __dirname,
port: 3000,
publicPath: "http://localhost:3000/dist/",
proxy: {
'/api' : {
target: 'http://localhost:8000',
secure: false
}
},
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebPackPlugin({
hash: true,
template: "./src/index.html",
filename: "index.html"
})
],
optimization: {
minimize: true,
minimizer: [new TerserPlugin()]
}
};
When I run webpack-dev-server, everything compiles fine, but when I navigate to localhost:3000/public/dist/index.html, I get a "file not found" error.
However, when I run webpack --mode development, the index.html file is correctly written to public/dist and I'm able to open it on my web browser.
I'm not sure why this file is correctly written when webpack is run normally, but not when the dev server is ran. I know the webpack dev server serves files from memory so I don't expect it to show up on my filesystem but I at least expect to be able to open it from the browser.
Thanks!

Webpack dev server doesn't actually build the files to your project directory. From their docs:
webpack-dev-server doesn't write any output files after compiling. Instead, it keeps bundle files in memory and serves them as if they were real files mounted at the server's root path.
So running webpack-dev-server, you shouldn't expect to see any built files (like your resultant index.html) in your dist directory. It will be serving the project from memory directly to your localhost:3000, or whatever pathname you choose. However, running webpack actually builds the files to your destination directory, and you'll find them there. Hope that clears it up for you.

Related

uglifyjs not minifying the files (Webpack)

I have been trying to use uglify option using webpack, but my resultant page's size remains the same without minification.I tried the following things,
webpack.config
var webpack = require('webpack');
const Uglify = require("uglifyjs-webpack-plugin");
module.exports = {
entry: __dirname + '/app/index.js',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
output: {
filename: 'whattoname.js',
path: __dirname + '/build'
},
plugins: [
new Uglify()
]
};
I tried to set the mode to production
Ran the build using webpack -p command
Also with --optimize-minimizer command
The end file's size remains the same. Am I missing something here?
I had a similar issue, to resolve the problem I would suggest moving across to the inbuilt webpack uglifier as seen in the following example (no uglifier dependancy required):
var webpack = require('webpack');
module.exports = {
entry: __dirname + '/app/index.js',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
output: {
filename: 'whattoname.js',
path: __dirname + '/build'
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
minimize: true
})
]
};
If this does not resolve your issue I suggest several actions:
clean out your dist and recompile to insure the file is actually writing to dist
Inspect the dist code, to check if it appears uglified. It is possible your project was already uglifying the file somewhere else, which would mean the file size after uglification does not change
Adding the include: /\.js$/ field to your webpack.optimize.UglifyJsPlugin to specify precisely the targeted files
As for what caused this issue. I would suggest reading this comments posted here

Sourcemaps not mapping correctly except "entry" specified in webpack

I'm using ASP.NET Core 2.0. If anyone wants to see detailed code or run it themselves, the code can be found here: https://github.com/jakelauer/BaseballTheater/tree/master/BaseballTheaterCore
My basic problem is that I'm expecting each generated js file in my project to have a sourcemap back to the original .ts or .tsx file. That is not working except for my entry file (./ClientApp/boot.tsx).
Here is my webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const bundleOutputDir = './wwwroot/dist';
module.exports = (env) => {
const isDevBuild = !(env && env.prod);
return [{
stats: { modules: false },
entry: { 'main': './ClientApp/boot.tsx' },
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
output: {
path: path.join(__dirname, bundleOutputDir),
filename: '[name].js',
publicPath: 'dist/'
},
module: {
rules: [
{ test: /\.tsx?$/, include: /ClientApp/, use: 'awesome-typescript-loader?silent=true' },
{ test: /\.css$/, use: isDevBuild ? ['style-loader', 'css-loader'] : ExtractTextPlugin.extract({ use: 'css-loader?minimize' }) },
{
test: /\.scss/,
use: ["style-loader", "css-loader", "sass-loader"]
},
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [
new CheckerPlugin(),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(bundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin('site.css')
])
}];
};
Based on my interpretation of this file and limited understanding of webpack, this should work. Each of my files does generated a .js.map file, and it appears to be referenced in the generated .js file. However, none of them actually load except the one for boot.tsx when debugging in Chrome.
An example of one of the js files in Chrome:
And that file does have the correct files to load:
When I open main.js.map in /wwwroot/dist/ and Ctrl+F for ts inside there, I only find boot.tsx and none of the other .ts or .tsx files I would expect to find.
I am no webpack expert, so I'm not sure what else to do!
From the comments, we've come to the solution by:
upgrading to the newest webpack (v4 in this case) and
installing the source-map loader via npm install --save-dev source-map-loader and
setting devtool: 'source-map' in the webpack.config.js.
The source-map option tells webpack to emit a full separate source map file. This is from the webpack docs:
source-map - A full SourceMap is emitted as a separate file. It adds a reference comment to the bundle so development tools know where to find it.

Correct way to configure babel-loader in webpack for HMR

About a week ago I ran into a problem while adding HMR to my project, the problem was that it just didn't work, the console showed HMR Enabled and also detected changes on the files, but it didn't re-render the view, the console would log:
[HMR] Updated modules:
[HMR] - ./app/src/components/app.jsx
[HMR] App is up to date.
but nothing would change visually, neither in the code inspector.
After lots of experimenting I found out that the problem was being caused by the babel-loader, it somehow interfered with webpacks HMR motor or something like that. I solved it by excluding the index file in the babel loader, however I don't think that's the best approach since now I can't use some js features in my index.jsx file. I want to know if theres a better way to solve this issue, perhaps something in my configuration or in the way of setting up webpacks hot middleware.
This is my webpack configuration:
module.exports = {
resolve: {
extensions: ['*', '.js', '.jsx']
},
entry: [
'webpack-hot-middleware/client', './app/src/index.jsx'
],
output: {
path: path.resolve(__dirname, 'build/js'),
filename: 'bundle.js',
publicPath: '/public'
},
devtool: 'cheap-module-source-map',
module: {
rules: [{
test: /\.jsx?$/,
exclude: /node_modules/,
include: path.resolve(__dirname, 'app/src/'),
exclude: path.resolve(__dirname, 'app/src/index.jsx'),
use: [{
loader: 'babel-loader',
options: {
presets: [
'react-hmre'
],
plugins: [
'transform-object-rest-spread'
]
}
}],
}]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
]
}
And this is how I setup the hot middleware and react-hot-loader in my server:
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const webpackConfig = require('./webpack.dev.config')
const compiler = webpack(webpackConfig)
app.use(webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath
}))
app.use(webpackHotMiddleware(compiler))
Thanks in advance.
So it was the babel configuration as I thought, you need the option modules: false in the env preset so it lets webpack handle the modules, it is a noob mistake but man, it drove me crazy for days.
The correct config for the env preset its like so:
['env', {modules: false}]

webpack configuration webpack-dev-server does not compile files on the fly

I have following webpack configuration file.
const path = require('path');
const webpack = require('webpack');
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'scripts.min.js'
},
resolve: {
root: [
path.resolve('./src'),
path.resolve('./node_modules')
]
},
entry: './src/app.js',
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel'
}
]
},
devServer: {
// compress: true,
inline: true,
stats: 'errors-only'
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ 'mangle': false, sourcemap: false })
]
};
The problem is that when I run webpack-dev-server command, it does run the server but when I make changes to any js file they are not compiled on the fly. So I had to stop the server and run webpack and then run webpack-dev-server command to make things work.
How can I make webpack-dev-server work so that when watches for all js, css, scss files and compile those fly?
If you are working with an IDE, you have to disable "safe write".
Note that many editors support “safe write” feature and have it enabled by default, which makes dev server unable to watch files correctly. “Safe write” means changes are not written directly to original file but to temporary one instead, which is renamed and replaces original file when save operation is completed successfully. This behaviour causes file watcher to lose the track because the original file is removed. In order to prevent this issue, you have to disable “safe write” feature in your editor.
http://webpack.github.io/docs/webpack-dev-server.html#hot-mode

Include assets from webpack bundled npm package

I've been banging my head over this for a while, and am wondering if it's even possible to begin with. Thanks for any help with this!
The npm package
I've got an npm package which is basically a library of React components. This library has embedded stylesheets, which references assets like fonts and images from the CSS. These are then all bundled using webpack into my-package.js.
The config for this looks like:
var path = require('path');
module.exports = {
module: {
loaders: [
{
test: /\.js$/,
loaders: ['babel-loader'],
exclude: /node_modules/
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
loader: 'file-loader'
},
{
test: /\.styl$/,
loader: 'style-loader!css-loader!stylus-loader'
}
]
},
entry: [
'./lib/components/index.js',
'./lib/index.styl'
],
output: {
path: path.join(__dirname, 'build/'),
filename: 'my-package.js'
}
}
With ./lib/components/index.js looking like:
import '../index.styl';
import MyComponent from './my-component.js';
export {
MyComponent
}
So far, so good.
The application
Now in another code base I've got the main application, which install this npm package.
My application root requires this package...
import MyPackage from 'my-package';
And is then itself webpack bundled and loaded onto the browser. All the scripts and style blocks are bundled correctly, however the styles which reference the assets are using the relative url from the npm package itself, therefore giving me 404s from the application.
console errs
Is there any way to tell webpack to resolve these images from node_modules/my-package/build/[webpack-generated-name].jpg ?
My application's webpack config looks like this:
var path = require('path'),
webpack = require('webpack');
module.exports = {
devtool: '#eval-source-map',
entry: [
'my-package',
'webpack/hot/only-dev-server',
'./app/index.js',
],
output: {
path: path.join(__dirname, 'build/static'),
filename: 'bundled.js',
publicPath: '/',
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
resolve: {
extensions: ['', '.js']
},
resolveLoader: {
'fallback': path.join(__dirname, 'node_modules')
},
module: {
loaders: [
{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
exclude: /node_modules/,
include: __dirname
},
{
test: /\.css?$/,
loader: "style-loader!css-loader",
include: __dirname
},
{
test: /\.(jpg|jpeg|ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
loader: 'file-loader'
},
{
test: /\.styl$/,
loader: 'style-loader!css-loader!stylus-loader'
}
]
}
};
Figured out a way around this.
In my application's webpack config I added a plugin (recommended by #Interrobang) which copies the static assets from the node_module/my-package into the app server's public path:
var TransferWebpackPlugin = require('transfer-webpack-plugin');
...
plugins: [
new TransferWebpackPlugin([
{ from: 'node_modules/my-package/assets', to: path.join(__dirname, 'my/public') }
])
]
...
These will then be made accessible by calling the asset name: localhost:XXXX/my-image.jpg. The server here is basically looking at /my/public/my-image.jpg if you've set it up correctly.
I'm using Express, so I just had to define app.use(express.static('my/public')) in my app server.
When bundling your NPM package, you could inline all the static assets into your final bundle. That way, your index.js that Webpack bundles for you would have all the static assets it needs, and simply importing that wherever you need your React components would do the trick.
The best way to inline static assets as of Webpack 5 is by using the "asset/inline" module from Asset Modules, which you can read about here: https://webpack.js.org/guides/asset-modules/
Simply put, your webpack.config.js should have a section as such:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
type: 'asset/inline'
}
]
},
};
What really relates to your question here is the test for png, jpg, and gif files which uses the asset/inline module.
The post here https://stackoverflow.com/a/73417058/14358290 explains it with slightly more detail.
Other plugins that copy such files from your /node_modules to /build directory are hacky and create packages that are not really distributable - everyone else that uses the said package would have to set up their Webpack to do the same copying operation. That approach can be avoided now that Webpack 5 solves this problem for us.

Categories

Resources