I've been working on an app using React and Webpack for a little while. My development environment works fine, and everything loads properly using webpack-dev-server.
I decided to run a production build of the application to see what the end-product might look like size-wise and observe the general output of the webpack product build.
It turns out that running webpack -p, while it does produce output (more on that in a minute), does not load anything at all when I hit the site in a browser.. A quick check of the output tells me that none of my component code is making it into the webpack -p build.
The images and HTML copy over as they exist in my src (dev) folder, however my JS bundle output is extremely small - the file (main.js) is only 246 bytes.
Here is the output from running webpack -p
$ npm run build
> project#0.1.0 build /Users/me/Development/project
> NODE_ENV=production webpack -p --bail --progress --config webpack.config.babel.js
Hash: 9e5f6974ce21c920a375
Version: webpack 1.12.10
Time: 2003ms
Asset Size Chunks Chunk Names
index.html 1.45 kB [emitted]
images/edit.svg 524 bytes [emitted]
images/search.svg 1.19 kB [emitted]
main.js 246 bytes 0, 1 [emitted] javascript, html
+ 219 hidden modules
When I run the development version of the project, the output is markedly different... I know that the dev server dependencies are in there, and the code is not minified.. And, most importantly - everything works as expected when running the dev server.
$ npm start
> project#0.1.0 start /Users/me/Development/project
> webpack-dev-server --hot --display-modules --config webpack.config.babel.js
http://localhost:3333/
webpack result is served from /
content is served from /Users/me/Development/project/dist
Hash: 1b34ed58f9e323966ada
Version: webpack 1.12.10
Time: 2745ms
Asset Size Chunks Chunk Names
index.html 1.45 kB [emitted]
images/edit.svg 524 bytes [emitted]
images/search.svg 1.19 kB [emitted]
main.js 1.54 MB 0, 1 [emitted] html, javascript
Here's my webpack.config.babel.js file:
import webpack from 'webpack';
import path from 'path';
import ModernizrWebpackPlugin from 'modernizr-webpack-plugin';
import modernizrConfig from './modernizr.config';
const appDir = path.resolve(__dirname, './src');
const distDir = path.resolve(__dirname, './dist');
const nodeModulesDir = path.resolve(__dirname, './node_modules');
const excludeDirs = /(node_modules|bower_components)/;
module.exports = {
entry: {
javascript: appDir + '/main.js',
html: appDir + '/index.html'
},
output: {
path: distDir,
filename: 'main.js',
},
devServer: {
contentBase: distDir,
inline: true,
port: 3333
},
resolve: {
extensions: ['', '.js', '.es6'],
modulesDirectories: [
'node_modules',
'./src'
]
},
plugins: [
// new webpack.optimize.CommonsChunkPlugin('common.js'),
// new ModernizrWebpackPlugin(modernizrConfig),
],
sassLoader: {
sourceMap: false,
includePaths: [
appDir,
nodeModulesDir,
nodeModulesDir + '/breakpoint-sass/stylesheets/',
nodeModulesDir + '/susy/sass'
]
},
module: {
loaders: [
{ // js/jsx
test: /\.js?$/,
exclude: excludeDirs,
loader: 'babel',
query: {
cacheDirectory: true,
presets: [
'es2015', 'react'
]
}
},
{ // html
test: /\.html$/,
exclude: excludeDirs,
loader: 'file?name=[name].[ext]'
},
{ // images
test: /\.(gif|png|jpg|jpeg|svg)$/,
exclude: excludeDirs,
loader: 'file?name=images/[name].[ext]'
},
{ // sass
test: /\.scss$/,
exclude: excludeDirs,
loader: 'style!css!sass'
}
]
}
}
I don't think I've got a particularly complex, or uncommon setup, and I've tried changing everything from es2015/es6 to commonJS already as well, with the same result.
I'm at a loss as to what the issue could possibly be here; hoping that someone can point out some obvious error I've got, or perhaps suggest config updates/changes that could resolve this problem.
Thanks for taking the time to read everything!
As I mentioned in my comment, I've been using webpack successfully for months now, and I've never come across using an HTML file as an entry point.
Usually you'll use Webpack to package up javascript, css, and sometimes images (ie: "assets") to be used by an html file. Serving that HTML file is outside the realm of Webpack's responsibility.
I would suggest using Webpack to generate only the final javascript bundle, then using some other method (ie: express, or some other web server) to serve that file and the html that consumes it.
Related
What I want to do:
Exclude my node_modules from being bundled by Webpack 4 (not just the babel-loader).
My current production bundle size:
Version: webpack 4.42.0
Time: 34941ms
Built at: 09/23/2020 2:05:13 PM
Asset Size Chunks Chunk Names
./public/bundle.js 4.87 MiB 0 [emitted] [big] bundle
Entrypoint bundle [big] = ./public/bundle.js
My current development bundle size:
Version: webpack 4.42.0
Time: 10780ms
Built at: 09/23/2020 1:50:15 PM
Asset Size Chunks Chunk Names
./public/bundle.js 10.4 MiB bundle [emitted] bundle
./public/bundle.js.map 11.2 MiB bundle [emitted] [dev] bundle
Entrypoint bundle = ./public/bundle.js ./public/bundle.js.map
To my knowledge, 4.87 MiB and 10.4 MiB are MASSIVE for a webpack bundle.
My current production webpack config:
'use strict'
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()
const TerserPlugin = require('terser-webpack-plugin')
module.exports = smp.wrap({
mode: 'production',
entry: {
'bundle': './client/index.js',
},
output: {
path: __dirname,
filename: './public/[name].js'
},
optimization: {
minimizer: [new TerserPlugin({
include: /\.js$/,
})],
minimize: true
},
context: __dirname,
devtool: 'source-map',
module: {
rules: [
{
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['react', 'env']
}
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
})
What I have tried:
Using webpack-node-externals
target: 'node', // I've also tried target: 'web' as well.
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
This successfully excludes node_modules, BUT causes a breaking error in my app:
Uncaught ReferenceError: require is not defined
at Object.react (external "react":1)
at __webpack_require__ (bootstrap:19)
at Object../client/index.js (index.js:1)
at __webpack_require__ (bootstrap:19)
at bootstrap:83
at bootstrap:83
I've read into this and it seems that this webpack-node-externals package should not be used for web applications. Removing the externals prop, and toggling target between 'node' and 'web' does not exclude my node_modules successfully.
Am I doomed here? Do I simply have a huge application and should not expect to get the bundle size down any further from 4.87 MiB for production and 10.4 MiB for development? It seems extremely large based on everything I've read.
I have a React application, and in my application I'm relying on react-scripts, so the build command is defined like this "build": "react-scripts build", and it works all fine. Now, the point is that inside my src directory I have a JS file called wrapper.js, which is a standalone file, and it is pure JS, no React stuff, but it uses ES6 and some newer features. So, what I want to do is that, I want create a new command, which will transpile and minify this file and will create a standalone copy of it. I thought to use webpack and I created a webpack.config.js file in the root of my project, which looks like this:
const path = require('path');
const MinifyPlugin = require('babel-minify-webpack-plugin');
module.exports = {
mode: 'production',
output: {
path: __dirname + 'build',
publicPath: '/build/',
filename: 'wrapper.js',
},
module: {
rules: [
{
test: /\.js$/,
include: [
path.resolve(__dirname, 'src', 'wrapper.js')
],
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}
]
},
plugins: [
new MinifyPlugin()
]
};
And I added the following to my package.json file "wrapper": "webpack". Now, when I run npm run-scripts wrapper, it executes the webpack command, but it throws error. The output looks like this:
> webpack
Hash: 0aa67383ec371b8b7cd1
Version: webpack 4.19.1
Time: 362ms
Built at: 04/06/2019 10:54:46 AM
1 asset
Entrypoint main = wrapper.js
[0] ./src/index.js 223 bytes {0} [built] [failed] [1 error]
ERROR in ./src/index.js 22:4
Module parse failed: Unexpected token (22:4)
You may need an appropriate loader to handle this file type.
|
| ReactDOM.render(
> <Root />,
| document.getElementById('root'),
| );
What I see is that the problem is that webpack also tries to transpile and minify other files in my src directory, because it seems it has hit my React app's index.js file. How can I exclude everything? Or more precisely, how can I tell webpack to transpile and minify only the file /src/wrapper.js, and not to touch anything else at all?
Lighter weight alternative could be to create a script in your package.json and use babel-minify, https://babeljs.io/docs/en/babel-minify
package.json
{
...
"scripts": : {
"minify": "minify wrapper.js --out-file wrapper.min.js --mangle.keepClassName"
}
...
}
Add entry object to your webpack.config.js.
module.exports={
entry: './src/wrapper.js',
...
}
webpack points the entry object by default to ./src/index.js.
So if you don't override entry object, webpack will bundle the file in ./src/index.js
Update
To point to a output directory properly
output: {
filename: 'wrapper.js',
path: path.resolve(__dirname, 'build')
}
Can anyone direct me in the right direction?
So i've setup the webpack-dev-server with the truffle suite demo, just to get a basis on the foundation of my app. So my config file includes index.html & app.js, yet it try to display a console.log output to from app.js nothing shows via the console?
webpack.config.js
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports =
{
entry: './app/javascripts/app.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'app.js',
},
plugins: [
// Copy our app's index.html to the build folder.
new CopyWebpackPlugin([
{ from: './app/index.html', to: "index.html" }
])
],
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
],
loaders: [
{ test: /\.json$/, use: 'json-loader' },
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015'],
plugins: ['transform-runtime']
}
}
]
},
devServer: {
compress: true,
disableHostCheck: true, // That solved .
quiet: false,
noInfo: false,
stats: {
// Config for minimal console.log mess.
colors: true,
version: false,
hash: false,
timings: false,
chunks: false,
chunkModules: false
}
}
}
app.js
// Import libraries we need.
import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
// Import our contract artifacts and turn them into usable abstractions.
import metacoin_artifacts from '../../build/contracts/MetaCoin.json'
import dextre_artifacts from '../../build/contracts/Dextre.json'
console.log("starting!");
Output when running webpack
Project is running at http://localhost:8080/
webpack output is served from /
Asset Size Chunks Chunk Names
app.js 1.93 MB 0 [emitted] [big] main
index.html 19.8 kB [emitted]
webpack: Compiled successfully.
Where can view the "starting!" output, this is a real annoyance as i need to tackle errors. I've tried viewing at http://localhost:8080// and http://localhost:8080/webpack-dev-server//, but no luck.
I had this same problem. As far as I can tell, the problem is that Webpack does not actually run the generated code on the server. The process that runs on the server simply checks for file changes and re-compiles when necessary. The code is actually all running on the client. So, the only way to view output from console.log() is to view the client browser's console.
Part of the confusion here is that while normally, node runs javascript on the server, in this case, node is delegating to a separate program entirely. You can run this whole thing without node installed at all, just using a standalone installation of the webpack executable. Node's execution environment is never used, thus you can't log to it.
Since you are using webpack-dev-server the console.log is gonna be printed into the browser console. If you want to see console.log printed in your terminal you can add a console.log inside webpack.config file.
If you are not providing the webpack-dev-server a port your app should run on 80 so opening the browser there and opening the browser console and you should be able to see the "starting! log.
I have recently taken over a frontend project, and noticed that the initial start time for the dev script (with hot module reloading etc) takes extremely long, ~2 minutes.
After setting verbose to true, I realised almost all of this time is spent recompiling CSS and images which haven't even changed.
The output of the webpack build is a long list that looks like this:
---------
Webpack stdout for /Users/myuser/Documents/repos/myApp-frontend/client/modules/App/background.jpg
---------
Hash: 0f500227a855ef9eb67c
Version: webpack 2.1.0-beta.8
Time: 68ms
Asset Size Chunks Chunk Names
.webpack.res.1504199219496_875923.js 132 kB 0 [emitted] main
+ 1 hidden modules
---------
Webpack stdout for /Users/myuser/Documents/repos/myApp-frontend/client/modules/App/AppAuthorized.css
---------
Hash: 83f1c479b77c7539baeb
Version: webpack 2.1.0-beta.8
Time: 549ms
Asset Size Chunks Chunk Names
.webpack.res.1504199221679_732531.js 23.2 kB 0 [emitted] main
+ 5 hidden modules
The images seem to process quickly, but each of these 2kb css files is taking half a second to compile, and there are dozens of them.
Here's what my webpack config looks like:
var cssnext = require('postcss-cssnext');
var postcssFocus = require('postcss-focus');
var postcssReporter = require('postcss-reporter');
var precss = require('precss');
var syntax = require('postcss-scss');
module.exports = {
output: {
publicPath: '/',
libraryTarget: 'commonjs2',
},
resolve: {
extensions: ['', '.js', '.jsx'],
modules: [
'client',
'node_modules',
],
},
module: {
loaders: [
{
test: /\.css$/,
exclude: /node_modules/,
loader: 'cache-loader!style-loader!css-loader?localIdentName=[name]__[local]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader',
},
{
test: /\.jpe?g$|\.gif$|\.png$|\.svg$/i,
exclude: /node_modules/,
loader: 'cache-loader!url-loader?limit=9999999999999',
},
{
test: /\.ico$/,
loader: 'file-loader?name=[name].[ext]'
},
],
},
postcss: () => ({
plugins: [
precss(),
postcssFocus(),
cssnext({
browsers: ['last 2 versions', 'IE > 10'],
}),
postcssReporter({
clearMessages: true,
}),
],
syntax: syntax,
}),
};
Any advice to speed the CSS compilation up, or cache assets somehow?
To improve the performance of Webpack build / hot-reloading, I usually check the following list and make sure I am doing the right thing:
For dev mode env, set the correct 'source-map'. Normally, I go with 'eval' which seems to be the fastest. You can find the benchmark here: https://webpack.js.org/configuration/devtool/?_sm_au_=iHV0NZ57NZfZ44WQ
For dev mode env, remove all the optimisation plugins as they take extra time and only use them in production.
For dev mode env, check the version of loaders in package.json, especially for css-loader, style-loader and sass-loader because some latest version may slow down the build. Check https://github.com/webpack-contrib/css-loader/issues/124 for more details.
Upgrading to Babel 6 may give 10%-20% performance boost.
Use webpack-dev-server for dev mode env.
Always run 'npm outdated' to check any modules are too old.
Make sure the computer is not running too slow. Try to restart.
I'm having some issues getting Webpack's live reloading working. I believe I have everything setup correctly. The problem is when saving files the browser refreshes but no changes are displayed.
I run the webpack development server with the following command:
webpack-dev-server --inline
And I start my PHP development server with this command:
php -S localhost:8000 -t public/
In my public/index.php file include the webpack-dev-server.js file:
<script src="http://localhost:8080/webpack-dev-server.js"></script>
When I make a changes to entry.js and hit save I can see the files recompiling and the browser refreshes. Except no changes are made.
I get the following output at the terminal when saving entry.js:
Time: 44ms
Asset Size Chunks Chunk Names
app.js 240 kB 0 [emitted] main
app.css 42.4 kB 0 [emitted] main
chunk {0} app.js, app.css (main) 222 kB [rendered]
[75] ./src/js/entry.js 108 bytes {0} [built]
+ 77 hidden modules
webpack: bundle is now VALID.
webpack: bundle is now INVALID.
Hash: 3937d6fc90a1794a8daa
Version: webpack 1.13.3
I tried to add a simple alert("Testing"); to entry.js but got no popup. If I check the webpack-dev-server.js file for any line that contains the word Testing it finds non.
Here is the contents of webpack.config.js:
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const path = require('path');
module.exports = {
context: __dirname,
entry: path.join(__dirname, '/src/js/entry.js'),
output: {
path: path.join(__dirname, '/public'),
filename: "app.js"
},
module: {
loaders: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader')
},
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['es2015']
}
},
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }
]
},
postcss: [
require('postcss-import'),
require('postcss-nested'),
require('autoprefixer'),
require('precss'),
require('postcss-custom-media'),
require('lost')
],
plugins: [
new ExtractTextPlugin('app.css')
]
};
Is there anything I'm doing wrong?
Edit: Also tried the following:
php -S localhost:8000 -t public starts the webserver. webpack-dev-server --content-base=public --inline --hot --watch" starts the webpack-dev-server. I load localhost:8000/index.php and monitor the console inspector. I can see that hot module replacement is enabled. If I modify and save entry.js and include a simple alert('Hello'); I can see in the web console that it's recompiling. The page refreshes, yet nothing happens. No changes to be seen.