React project bundle size is too large although used all compression technique it takes too time to load first index page.First browser download bundle js and then load page.How to load index page first then other component bundle.
Following is webpack.js
module.exports = {
devtool: 'source-map',
context: path.resolve(__dirname, '..'),
entry: {
'main': [
'bootstrap-sass!./src/theme/bootstrap.config.prod.js',
'font-awesome-webpack!./src/theme/font-awesome.config.prod.js',
'./src/client.js'
]
},
output: {
path: assetsPath,
filename: '[name]-[chunkhash].js',
chunkFilename: '[name]-[chunkhash].js',
publicPath: ''
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: [strip.loader('debug'), 'babel']},
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader')},
{ test: /\.less$/, loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=2&sourceMap!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap=true&sourceMapContents=true') },
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=2&sourceMap!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap=true&sourceMapContents=true') },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" },
{ test: webpackIsomorphicToolsPlugin.regular_expression('images'), loader: 'url-loader?limit=10240' },
{ test: /\.html$/, loader: 'html-loader' }
]
},
progress: true,
resolve: {
modulesDirectories: [
'src',
'node_modules'
],
extensions: ['', '.json', '.js', '.jsx']
},
plugins: [
// css files from the extract-text-plugin loader
new ExtractTextPlugin('[name]-[chunkhash].css', {allChunks: true}),
// ignore dev config
new webpack.IgnorePlugin(/\.\/dev/, /\/config$/),
// optimizations
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
webpackIsomorphicToolsPlugin
]
Please prefer the dynamic import function to split your code easily and without changing much. As a general guideline, dynamically import all of your top route components. When combined with pre-loaded modules, this will be a very effective tool for splitting your code fast and effectively.
When you do this, you can use any of the available load wrapper libraries like react-loadable to display a waiting component while your actual component is being imported.
An example (https://reacttraining.com/react-router/web/guides/code-splitting):
import Loadable from 'react-loadable';
import Loading from './Loading';
const LoadableComponent = Loadable({
loader: () => import(
/* webpackPreload: true */
/* webpackChunkName: "dashboard" */
'./Dashboard'
),
loading: Loading,
})
export default class LoadableDashboard extends React.Component {
render() {
return <LoadableComponent />;
}
}
In the above example, magic-comments are used to define the pre-load behavior and split chunk-name. Read more about these here.
Use dynamic imports to split your non-react code as well, e.g. stores.
You can follow strategy of code splitting for effective load.
The open source library react-loadable provides a React-friendly API for code splitting,
Here is a link for a blog related to that:-
https://hackernoon.com/effective-code-splitting-in-react-a-practical-guide-2195359d5d49
Hope it helps.
Related
I am trying to get Webpack to render a static html and export relative css, starting from a pug template and css modules using HtmlWebpackPlugin.
My setup is as follow
//webpack.config.js
...
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "src/templates/index.pug",
excludeChunks: ["landing", "runtime"],
excludeAssets: [/index.*.js/]
})
new HtmlWebpackExcludeAssetsPlugin(),
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
chunkFilename: "[name].[contenthash].css"
})
]
module: {
rules: [
/**
* pug
*/
{
test: /\.pug$/,
exclude: /node_modules/,
use: ["pug-loader"]
},
/**
* scss
*/
{
test: /\.scss$/,
exclude: /node_modules|_.+.scss/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: process.env.NODE_ENV === "development"
}
},
{
loader: "css-loader",
options: {
modules: true,
localsConvention: "camelCase",
sourceMap: true
}
},
"postcss-loader",
"sass-loader"
]
}
]
}
...
Then in my index.pug file I would like to do something like this:
- var styles = require("../styles/style.module.scss")
div(class=styles.someClass)
The problem is that if I leave the configuration as is, I get
ERROR in ./src/styles/style.module.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
TypeError: this[MODULE_TYPE] is not a function
I managed to correctly get the transformed class names in the pug template by doing
/**
* scss
*/
{
test: /\.scss$/,
exclude: /node_modules|_.+.scss/,
use: [
//{
// loader: MiniCssExtractPlugin.loader,
// options: {
// hmr: process.env.NODE_ENV === "development"
// }
//},
{
loader: "css-loader",
options: {
modules: true,
localsConvention: "camelCase",
sourceMap: true,
onlyLocals: true <=====
}
},
"postcss-loader",
"sass-loader"
]
}
But by removing MiniCssExtractLoader from the chain I obviously don't get the exported css file.
By setting onlyLocals: true, classes in pug work as expected because css-loader exports the mappings.
If I remove - var styles = require("../styles/style.module.scss") from pug template and leave MiniCssExtractPlugin in the loaders' chain I get the opposite: css file, but no mappings.
Any idea? Is there a way to export the css file and get mappings back directly in the pug template?
P.S.
I have also come across this example from pug-loader's GitHub page
var template = require("pug-loader!./file.pug");
// => returns file.pug content as template function
// or, if you've bound .pug to pug-loader
var template = require("./file.pug");
var locals = { /* ... */ };
var html = template(locals);
// => the rendered HTML
Thought template(locals) would inject the locals into the template but I might have misinterpreted, since the html returned have unchanged classes' names, thus problem persists.
Just found out, all it takes is inlining the loaders applied in the pug template
- var styles = require("!css-loader?modules&onlyLocals&localsConvention=camelCase!postcss-loader!sass-loader!../styles/style.module.scss")
and having the Webpack configuration to export the css file
entry: {
index: ["./src/styles/style.module.scss"]
},
module: {
rules: [
/**
* scss
*/
{
test: /\.scss$/,
exclude: /node_modules|_.+.scss/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: process.env.NODE_ENV === "development"
}
},
{
loader: "css-loader",
options: {
modules: true
}
},
"postcss-loader",
"sass-loader"
]
}
]
},
If anyone knows a better solution to make use of source maps please post it.
I am building a component library and I am using Webpack to bundle it. Some components only rely on html templates, css and JavaScript that I've written, but some components require external libraries.
What I'd like to achieve is a vendor.js that is optional to include if the component you want to use needs it.
For instance, If a user only needs a component without vendor dependencies, it would suffice that they use main.bundle.js which only contains my own code.
In my index.js, I have the following imports:
import { Header } from './components/header/header.component';
import { Logotype } from './components/logotype/logotype.component';
import { Card } from './components/card/card.component';
import { NavigationCard } from './components/navigation-card/navigation-card.component';
import { AbstractComponent } from './components/base/component.abstract';
import { Configuration } from './system.config';
import 'bootstrap-table';
import './scss/base.scss';
All of these imports are my own, expect for bootstrap-table.
I have configured Webpack like this:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractScss = new ExtractTextPlugin({
filename: "[name].bundle.css"
});
module.exports = {
entry: {
main: './src/index.ts'
},
output: {
path: path.resolve(__dirname, 'dist/release'),
filename: "[name].bundle.js",
chunkFilename: "[name].bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', // Specify the common bundle's name.
minChunks: function (module) {
// Here I would like to tell Webpack to give
// each bundle the ability to run independently
return module.context && module.context.indexOf('node_modules') >= 0;
}
}),
extractScss
],
devtool: "source-map",
resolve: {
// Add `.ts` as a resolvable extension.
extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
},
module: {
rules: [
// All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.ts?$/, exclude: /node_modules/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
// Allows for templates in separate ejs files
{test: /\.ejs$/, loader: 'ejs-compiled-loader'},
{
test: /\.scss$/,
use: extractScss.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
soureMap: true
}
}]
})}
]
}
}
This results in two .js files and one .css. However, webpacks common module loading functionality resides in vendor.js, and that renders my main unusable if I don't include vendor first, and it isn't always needed.
To sum it up, if a user only needs the footer (no external dependencies), this would suffice:
<script src="main.bundle.js"></script>
If the user wants to use the table, which has an external dependency, they would need to include both:
<script src="vendor.js"></script>
<script src="main.bundle.js"></script>
Right now, including only main.bundle.js gives me this error:
Uncaught ReferenceError: webpackJsonp is not defined.
I am aware that I can extract all common functionality by adding this after my vendor chunk is created in the Webpack config:
new webpack.optimize.CommonsChunkPlugin({
name: 'common'
})
But this approach still requires the user to include two .js files.
How can I go about achieving this? It seems that it only differs 2 kb when I don't extract the common modules like I do above, and that is fine with me.
Turns out this is very easy to do if you can stand some manual work and actually understand what Webpack does (which I didn't). I solved it like this:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractScss = new ExtractTextPlugin({
filename: "[name].bundle.css"
});
module.exports = {
entry: {
main: './src/index.ts',
vendor: './src/vendor/vendor.ts'
},
output: {
path: path.resolve(__dirname, 'dist/release'),
filename: "[name].bundle.js",
chunkFilename: "[name].bundle.js"
},
plugins: [
extractScss
],
devtool: "source-map",
resolve: {
// Add `.ts` as a resolvable extension.
extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
},
module: {
rules: [
// All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.ts?$/, exclude: /node_modules/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
// Allows for templates in separate ejs files
{test: /\.ejs$/, loader: 'ejs-compiled-loader'},
{
test: /\.scss$/,
use: extractScss.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
soureMap: true
}
}]
})}
]
}
}
In vendor.ts, I then simply import any vendor dependencies I have:
import 'jquery';
import 'bootstrap-table';
This results in two different files, both have Webpacks bootstrapping logic.
Hope this helps someone.
I'm debugging a javascrip code in chrome, but the chrome doesn't let me put breakpoints where I want. I click to put the breakpoint and he puts it some lines before or after the line that a clicked.
I click the line 94, and he puts a break in line 96.
the code in chrome
what do I do to debug it?
some help please.
Down here is the webpack.config.development.js
import path from 'path';
import webpack from 'webpack';
import validate from 'webpack-validator';
import merge from 'webpack-merge';
import formatter from 'eslint-formatter-pretty';
import baseConfig from './webpack.config.base';
const port = process.env.PORT || 3000;
export default validate(merge(baseConfig, {
debug: true,
devtool: 'eval-source-map',
entry: [
`webpack-hot-middleware/client?
path=http://localhost:${port}/__webpack_hmr`,
'babel-polyfill',
'./app/styles/main.less',
'./app/index'
],
output: {
publicPath: `http://localhost:${port}/dist/`
},
resolve: {
fallback: path.join(__dirname, 'node_modules')
},
resolveLoader: { fallback: path.join(__dirname, 'node_modules') },
module: {
loaders: [
{
test: /\.(less|scss)$/,
loader: 'style!css!autoprefixer!less'
},
// Load images
{ test: /\.jpg/, loader: 'url-loader?limit=10000&mimetype=image/jpg' },
{ test: /\.gif/, loader: 'url-loader?limit=10000&mimetype=image/gif' },
{ test: /\.png/, loader: 'url-loader?limit=10000&mimetype=image/png' },
{ test: /\.svg/, loader: 'url-loader?limit=10000&mimetype=image/svg' },
// Load fonts
{ test: /\.woff(\?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' },
]
},
eslint: {
formatter
},
plugins: [
// https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
new webpack.HotModuleReplacementPlugin(),
// “If you are using the CLI, the webpack process will not exit with an error code by enabling this plugin.”
// https://github.com/webpack/docs/wiki/list-of-plugins#noerrorsplugin
new webpack.NoErrorsPlugin(),
// NODE_ENV should be production so that modules do not perform certain development checks
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
],
// https://github.com/chentsulin/webpack-target-electron-renderer#how-
this-module-works
target: 'electron-renderer'
}));
Use the debugger; statement in your code where you want it to pause, if you know where you want to put the breakpoints before running the code.
Make sure the console is open before debugging, because otherwise the breakpoints will be disabled.
I have a ReactJS application based off of this boilerplate.
I am simply trying to load and require or import a css file (to be embedded in <style> tag, as opposed to css link). Below are the two methods I have tried, and not ever both at the same time.
Method 1: Configure loaders in Webpack
These are all the loader configurations I have tried, but still resulted in this error: [require-hacker] Trying to load "something.css" as a "*.js"
dev.config.js
module: {
loaders: [
// loaders in here
]
}
{ test: /\.css$/, loader: "style!css" }
{ test: /\.css$/, loader: 'style-loader!css-loader'} from here
{ test: /\.css$/, loader: 'style!css!postcss' }
{ test: /\.css$/, loader: 'style!css?modules&localIdentName=[name]---[local]---[hash:base64:5]!postcss' }
{ test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}
]
}
{
test: /\.css$/,
loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap'
},
Method 2: Use loaders directly
If I remove the css loaders altogether, and instead call require('style!css!./something.css'), I get this error:
Error: Cannot find module 'style!css!./something.css'
---- # NOTE: ----
I am able to properly require my .scss files and its webpack loader configuration is below. But for some reason my css files don't want to play that way too.
{ test: /\.scss$/,
loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap' }
change extensions: ['less','scss'] to extensions: ['less','scss','css'] in webpack-isomorphic-tools.js at line 65.for more details you can see this
Like using ProvidePlugin to preload jQuery, is there a way to preload a third-party's css and js files instead of using import in the entry js file?
Why I would like to preload these files is that I am getting an error when importing jQuery-ui in the entry js file. Also, I think it is good to preload the libraries.
./assets/js/jquery-ui.min.js
Critical dependencies:
719:76-84 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.
# ./assets/js/jquery-ui.min.js 719:76-84
Thank you in advanced!
You should import third party css files at entry on webpack config. like example below:
module.exports = {
entry: {
'main': [
'bootstrap-sass!./src/theme/bootstrap.config.js',
'./src/client.js',
'./src/someCSSFILE.js'
]
},
output: {
path: assetsPath,
filename: 'bundle.js',
publicPath: 'http://' + host + ':' + port + '/dist/',
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel?' + JSON.stringify(babelLoaderQuery), 'eslint-loader']},
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.less$/, loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap' },
{ test: /\.scss$/, loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap' },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" }
]
}