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
Related
GitHub: https://github.com/Chirag161198/react-boilerplate 1
Here is the react boilerplate I’m trying to make from scratch.
I have bundled html with the react code but I’m not able to add styles (CSS).
I have heard about ExtractTextPlugin but not able to configure it.
Please suggest some way to add styles to it.
Thank you in advance.
You need to use style-loader and css-loader in your webpack.config.js
First, install these two packages via npm:
npm install style-loader, css-loader --dev
Then, create a styles.css in your src folder and append the following styles into the file (just for demo purpose, so you know it's working correctly):
body {
background-color: #ff4444;
}
Don't forget to import the css file in your src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import './styles.css'; // <- import the css file here, so webpack will handle it when bundling
ReactDOM.render(<App />, document.getElementById('app'));
And use style-loader and css-loader in your webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: { loader: 'babel-loader' },
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
};
If you don't see the correct output, you might need to restart the webpack dev server again. I have cloned your repo and made the changes like I mentioned above, it works.
As for ExtractTextPlugin, you will need this when bundling for a production build, you can learn more from their Repo
Hope it helps!
Hi Chirag ExtractTextPlugin works great but when it comes to caching and bundle hashing. Css bundle becomes 0 bytes. So they introduced MiniCssExtractPlugin which has tackled this issue. It is really important to cache static files as your app size increase by time.
import plugin first:
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
add these in your webpack config:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.scss$/,
use: [ 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}
]
}
plugins: [
new MiniCssExtractPlugin({
filename: 'style.css',
}),
new HtmlWebpackPlugin({
template: './src/index.html',
}),
Let me know you the issue still persists.
first you need to load style-loader and css-loader.Then you will add the following code in "rules" in webpack.config.js file.
{ test: /\.css$/,use: ['style-loader', 'css-loader']}
then import the "style.css" file location into the "index.js" file and for example:
import "./style.css";
When you package, "css" codes will be added in "bundle.js".
I am developing a webapp with NodeJS and webpack. It uses also ReactJS as a dependency. So let's call it simple ui webapp.
In my package.json I reference a package as a dependency which I want to use in the app. This package is not from npm, but it is developed by myself and resides on the same filesystem, local, which totally works fine. I am developing this package, lets call it ui-elements and the webapp in parallel, because I know I have to use the ui-elements in 10 about following webapp-style projects.
Back to the problem: The package gets imported when I npm install, so I have my local package inside the node_modules dir. Good.
This ui-elements-package is also bundled with webpack and contains some React components that use images as background images. Now, when I run ./node_modules/.bin/webpack inside the package folder (while developing the ui-elements package) the file-loader emits the resources into the res/ folder, like I want it to be in the webpack.config.js from the ui-elements package.
But since I want to use the ui-elements package inside my webapp, the resources reside deep inside the node_modules/ dir (node_modules/ui-elements/res).
My question:
How should my webpack.config.js in the webapp project be altered, to get the image resolving by the browser working?
And, am I thinking too complicated? I just want to build and use a package (containing some ui elements with background images), that i can reuse in React webapps. Is there a better approach?
I will paste the extracts of the webpack configs of both projects:
ui-elements
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'index.js',
libraryTarget: 'commonjs2',
path: __dirname
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.resolve(__dirname, 'src'),
exclude: path.resolve(__dirname, 'node_modules'),
use: [
'babel-loader'
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: 'res/img/[name].[ext]'
}
}
]
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
modules: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules')
],
}
};
webapp
webpack.config.js
const path = require('path');
module.exports = {
entry: './index.js',
output: {
filename: 'webapp.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: path.resolve(__dirname, 'node_modules'),
use: [
'babel-loader'
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
},
resolve: {
/*
* this entry makes me use a local working tree of the
* ui-elements package, which makes working easier, i don't
* have to switch projects, rebuild the package and update my
* dependencies in this webapp project
*/
/*
alias: {
"ui-elements": path.resolve(__dirname, 'libDev'),
},
*/
extensions: ['.js', '.jsx'],
modules: [
path.resolve(__dirname, 'src'),
// path.resolve(__dirname, 'libDev'),
path.resolve(__dirname, 'node_modules')
],
}
};
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.
I've spent hours attempting to get my Webpack config to compile Sass; it's kinda ridiculous. During my research I found dozens of Github issues, Stackoverflow posts, and blogs talking about how to use Sass with Webpack, and they all do it differently. Also, there are so many people with problems. I just think Webpack needs to be better documented. Ugh.
I figured out how to compile Sass and have Webpack serve it in memory from /static, but I want the class names to be locally scoped. Isn't that one of the benefits of modular CSS with React components?
Example of locally scoped: .foo__container___uZbLx {...}
So, this is my Webpack config file:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
devtool: 'source-map',
entry: {
bundle: './src/js/app'
},
output: {
path: __dirname,
filename: '[name].js',
publicPath: '/static'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new ExtractTextPlugin('[name].css', {allChunks: true})
],
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
loader: 'babel'
},
{
test: /\.scss$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
loader: ExtractTextPlugin.extract('style', 'css?sourceMap!sass')
}
]
}
};
I managed to get it to work for vanilla CSS:
{
test: /\.css$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
}
I don't really understand the parameter-like syntax with all the ? marks, and I don't know what to search for to find documentation pertaining to that.
This is what my React component looks like; just incase you want to see how I am importing the style:
import React, { Component } from 'react';
import s from './foo.css';
class Foo extends Component {
render() {
return (
<div className={s.container}>
<h1 className="title">Welcome!</h1>
<p className="body">This is a dummy component for demonstration purposes.</p>
</div>
);
}
}
export default Foo;
Also, I have three unrelated questions:
What's the point of output.path property if Webpack merely serves the file from memory by means of /static?
What's the point of webpack-dev-server if what I am doing here is adequate? From my understanding, webpack-dev-server is just for hot module replacement stuff, right? Just automatic refreshing?
Are my exclude and include properties redundant? From my understanding, excluding node_modules decreases the compilation time making it work quicker; less files to process.
I got it to work with this:
loader: ExtractTextPlugin.extract('style', 'css?modules&localIdentName=[name]__[local]___[hash:base64:5]!sass')
All I had to do was put !sass at the end of the query. I wish this stuff was better documented; can't find adequate docs anywhere...
I'm trying to create a React application with multiple entries using webpack and extract-text-webpack-plugin.
My config file looks like this,
const commonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const extractTextPlugin = require('extract-text-webpack-plugin');
let config = {
entry: {
app: './client/app.entry.js',
signIn: './client/sign-in.entry.js',
},
output: {
path: './server/public',
filename: '[name].js'
},
module: {
loaders: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
},
{
test: /\.css$/,
loader: extractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
}
]
},
resolve: {
modulesDirectories: ['node_modules', 'client'],
extensions: ['', '.js']
},
plugins: [
new commonsChunkPlugin('common', 'common.js'),
new extractTextPlugin('styles.css', { allChunks: true })
]
};
module.exports = config;
My problem is that extract-text-webpack-plugin only includes imported css files from the entry chunks, and not from submodules of the entry chunks.
So if app.entry.js has
import "./app-style.css";
import "./sub-module"; // This module has import "./sub-style.css";
then the styles from app-style.css gets bundled but not the styles from sub-style.css.
I haven't had this issue before when there's only been one entry file, so I'm wondering if having multiple entries requires another setup?
Something to also take into consideration is the use of CSSModules by the way the css-loader is used, which also could be a factor.
Any ideas?
I'm trying to solve similar problem, and i think it will be nice idea to document the solution and thoughts for those who has the same questions.
TextExtract plugin can work with chunks that have to be configured with commonchunks plugin, enable chunks support:
// Configuration of the extract plugin with chunks and naming
new ExtractTextPlugin("[name].css", { allChunks: true })
It's all ) Next thing is just configuration of the chunks (webpack is very flexible tool, everyone configure it for own needs. For an instance i'll show how i configure "vendour.css" and "application.css" build configuration based on "imports")
// Vendour chunks definition for vendor css
entry: {
vendor : ['./css/vendour.sass']
Example of entrypoint file.js
import "./css/vendor.sass"
import "./css/application.sass"
After build, webpack will create vendor.css (where you export vendour things with #import "~vendormodules/sass/alla") and application.css files.
Thanks,