Optimize packaging build speed (which development environment performance user is it)
HMR
HMR: Hot module replacement: When a module changes, only one module is repackaged (rather than all modules), which greatly improves the speed of construction
- Style files: can use HMR function: because style-loader is implemented internally ~ (MiniCssExtractPlugin is also implemented, will be tested later)
- Note: the HMR function can only handle other files that are not entry JS files.
if (module.hot) {
// Once module.hot is true, HMR is enabled. --> Make the HMR function code work
module.hot.accept('./print.js'.function() {
// The print.js method listens for changes in the print.js file, and when changes occur, other modules are not repackaged and built.
// The following callback functions are executed
print();
});
}
Copy the code
-
HTML files: the HMR function is disabled by default. At the same time, there are problems: THE HTML file cannot be hot updated ~ (do not need to do HMR function) Solution: Modify the entry entry to import the HTML file
Optimize code debugging source-map
Source-map: a technique that provides source-to-build-code mapping (mapping to trace source code errors if errors are made after a build)
module.exports = {
devtool: 'eval-source-map'
}
Copy the code
Commonly used are: [the inline - | hidden - | eval -] [nosources -] [being - [module -]] source - the map inline and external difference: 1. 2. Inline builds fasterCopy the code
- Source-map: External error code exact information and source code error location
- Inline-source-map: Inline only generates an inline source-map error code with accurate information and source code error location
- Hidden-source-map: external error code error cause, but no error location can trace the source code error, only the error location of the built code
- Eval-source-map: Inline generates a corresponding source-map for each file, all at the eval error code’s exact information and source code’s error location
- Nosource-source-map: Accurate information about external error code, but no information about source code or build code
- Cheap -source-map: External error code exact information and source code error locations are only exact lines
- Cheap-module-source-map: external error code exact information and source code error location module will add loader source map
Development environment: fast and debug friendly
- Speed (eval > the inline > being >…).
- eval-cheap-souce-map
- eval-source-map
- More debug friendly
- souce-map
- cheap-module-souce-map
- cheap-souce-map
In summary, the development environment is eval-source-map/eval-cheap-module-souce-map
The production environment
Should source code be hidden? Debugging should be more friendly. Inlining makes code bigger, so it’s not used in production
- Nosource-source-map Is hidden
- Hidden-source-map only hides the source code, prompting post-build code error messages
oneOf
Optimization point: every different type of file will be hit by loader during conversion, traversing all loaders in Module rules
Babel cache
- CacheDirectory: True makes the second packaged build faster
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'.options: {
presets: [['@babel/preset-env',
{
useBuiltIns: 'usage'.corejs: { version: 3 },
targets: {
chrome: '60'.firefox: '50'}}]],// Enable the Babel cache
// On the second build, the previous cache is read
cacheDirectory: true}}Copy the code
- File resource cache
-
Hash: A unique hash value is generated for each Wepack build.
Problem: Because JS and CSS use the same hash value. If repackaged, all caches will be invalidated. (Maybe I only changed one file)
-
Chunkhash: Hash value generated by chunk. If the package comes from the same chunk, then the hash value is the same.
Problem: JS and CSS have the same hash value, because CSS belongs to the same chunk because it was introduced in JS
-
Contenthash: Generates hash values based on file contents. Different files must have different hash values, so it is better to use the cache to make the code run online
-
Multi-process packaging thread-loader
module.exports = {
module: {
rules: [{test: /\.js$/,
exclude: /node_modules/,
use: [
/* Enable multi-process packaging. Process startup takes about 600ms and process communication is also overhead. Multi-process packaging is required only if the work takes a long time
{
loader: 'thread-loader'.options: {
workers: 2 // Process 2}}, {loader: 'babel-loader'}]}}Copy the code
externals
Reject third-party libraries to be packaged in, and introduce third-party libraries through CDN
Such as jquery
- Introduced in HTML
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
Copy the code
2. Configure in webpack.config.js
module.exports = {
externals: {
// Refuse to package jQuery
jquery: 'jQuery'}};Copy the code
dll
Use DLL technology for some libraries (third-party libraries: jquery, React, vue…) Pack separately
Configure the webpack file (webpack.dll. Js) for the third party library separately and start packing into the library
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
[name] --> jquery
// ['jquery'] --> The library is jquery
jquery: ['jquery'],},output: {
filename: '[name].js'.path: resolve(__dirname, 'dll'),
library: '[name]_[hash]' // What is the name of the contents exposed in the packaged library
},
plugins: [
// Package to generate a manifest.json --> provide and jquery mapping
new webpack.DllPlugin({
name: '[name]_[hash]'.// Map the exposed content name of the library to the library above
path: resolve(__dirname, 'dll/manifest.json') // Output file path})].mode: 'production'
};
Copy the code
Webpack. Config. Js file
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
entry: './src/index.js'.output: {
filename: 'built.js'.path: resolve(__dirname, 'build')},plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
// Tell Webpack which libraries are not included in the package, and change their names when used
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')}),// Package a file and import the resource automatically in HTML
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')})],mode: 'production'
};
Copy the code
Optimize the performance of code execution
tree shaking
Webpack Tree Shaking
Tree Shaking: Remove useless code, reduce code size. Because of ES6 modules, ES6 module dependencies are deterministic, independent of runtime state, and can be reliably analyzed statically. This is the foundation for Tree Shaking. So Tree shaking is a must for ES6 modularity:
1. Start the Production environment
Set mode: 'Production' in the Webpack configuration file,Copy the code
2. Set sideEffects in package.json
1. "sideEffects": false All code is tree shaking. Problem: CSS / @babel/polyfill files may get dry So we can use: "sideEffects": ["*.css", "*.less"]Copy the code
3. In webpack – config. Js
Optimization: {minimize: false // This cannot be set to false, otherwise tree shaking will not work}Copy the code
4. Caution when using export-defaut
Export default function mul(x, y) {console.log(' SSSSSSS '); return x * y; } function count(x, y) { return x - y; } index.js file: import mul from './test'; console.log(mul(2, 3)); Function mul(x, y) {console.log(' SSSSSSS '); function mul(x, y) {console.log(' SSSSSSS '); return x * y; } function count(x, y) { return x - y; } export {mul, count}; Index.js file: import test from 'test'; console.log(test.mul(2, 3)); Importing the file using export. Default in this way has no effect, and count will still be packed into the compressed fileCopy the code
Webpack Tree shaking does not clean IIFE
export function mul(x, y) { console.log('sss'); return x * y; } const square = (function (x) { console.log('square'); return x*x; } ()); export function count(x, y) { console.log('kkkkk'); return x - y; } Executing functions immediately will not be removed, but Webpack Tree shaking returns from IIFE will be cleaned if they are not used, keeping only console.log('square'); Webpack doesn't do flow analysis. It doesn't know what special things IIFE does, so it won't delete this part of the codeCopy the code
Why Does Babel cause Tree Shaking to fail
Success depends on your version of Babel. Simply put, if you use Babel 6, Tree Shaking does not work. If you use Babel 7 and above, Tree Shaking works.
We already know that CommonJS modules are not the same as ES6 modules. Babel transforms all modules into exports and require by default. We also know that Webpack is Tree shaking based on ES6 modules. So when we use Babel, we should turn this behavior off as follows:
//babel.rc
presets: [["env",
{ module: false}]]Copy the code
If it’s ES7, and loash is introduced, it needs to be introduced like this
import { pullAll } from 'lodash-es';
import pullAll from 'lodash/pullAll';
Copy the code
code split
- Multiple entry
module.exports = {
/ / a single entrance
// entry: './src/js/index.js',
entry: {
// Multiple entries: There is one entry, and the final output has a bundle
index: './src/js/index.js'.test: './src/js/test.js'}}Copy the code
- Set up the
module.exports = {
/* 1. The node_modules code can be packaged as a separate chunk of the final output 2. Automatic analysis of multi-entry chunks, whether there are public files. If so, it will be packaged into a single chunk */
optimization: {
splitChunks: {
chunks: 'all'}},mode: 'production'
};
Copy the code
- import
/* Dynamic import syntax: it is possible to package a file separately */
import(/* webpackChunkName: 'test' */'./test')
.then(({ mul, count }) = > {
// The file is successfully loaded ~
// eslint-disable-next-line
console.log(mul(2.5));
})
.catch(() = > {
// eslint-disable-next-line
console.log('File load failed ~');
});
Copy the code
Lazy loading/preloading
document.getElementById('btn').onclick = function() {
// Lazy loading ~ : files are loaded only when they are needed
// Prefetch: preloads the JS file before it is used
// Normal loading can be considered parallel loading (multiple files are loaded at the same time)
// Prefetch: Wait until other resources are loaded and the browser is free, then secretly load the resources
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) = > {
console.log(mul(4.5));
});
};
Copy the code
Pwa Progressive Web development application (accessible offline)
PWA: Progressive Web development applications (offline access)
In the WebPack configuration file
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
2. Delete the old ServiceWorker and generate a Serviceworker profile ~ */
clientsClaim: true.skipWaiting: true})]Copy the code
Js entry file
{"env": {"browser": {"env": {"env": Sw code must run on the server --> nodejs --> NPM I serve-g serve-s build start the server, expose all resources in the build directory as static resources */
/ / register serviceWorker
// Handle compatibility issues
if ('serviceWorker' in navigator) {
window.addEventListener('load'.() = > {
navigator.serviceWorker
.register('/service-worker.js')
.then(() = > {
console.log('Sw registered successfully ~');
})
.catch(() = > {
console.log('SW registration failed ~');
});
});
}
Copy the code