webpack
With 5 coming up soon, completely writing an optimized scaffold by hand is an indispensable skill.
- Writing Time
May 9, 2019
,webpack
version4.30.0
The latest version - Want to be reproduced must contact oneself to be reproduced through agree just can be reproduced thank!
- Put an end to
5 minutes
Let’s go into the principle first and then write the configuration, that will be much easier.
Implementation requirements:
- identify
JSX
file -
tree shaking
Tree shaker removes useless code -
PWA
Features, hot refresh, immediately after installation take over the browser after offline still allows access to the website can also be added from the phone to the desktop for use -
CSS
Modularity, not afraid of naming conflicts - Little pictures
base64
To deal with - File suffixes omitted
jsx js json
Etc. - Lazy load, load on demand, code segmentation
- support
less sass stylus
Such as pretreatment -
code spliting
Optimize the loading time of the first screen to prevent a file from being too large - Extract the common code and package it into one
chunk
- each
chunk
There is a correspondingchunkhash
Each file has a correspondingcontenthash
To facilitate the browser to distinguish between cache - Image compression
-
CSS
The compression - increase
CSS
Prefixes are compatible with various browsers - Package output for various different files under the specified folder
- The cache
babel
To speed up the compilation - One for each entry file
chunk
, packaged out corresponding to a file is alsocode spliting
- delete
HTML
Unnecessary contents such as comments on files - Remove old packaging code with each build
- will
CSS
The files are extracted separately - And so on…
-
webpack
The slogan on the Chinese website is: Make everything simple
Concept:
In essence,webpack
Is a modernJavaScript
Static module packagers for applications (module bundler
). whenwebpack
When working with an application, it recursively builds a dependency graph (dependency graph
), which contains every module your application needs, and then packages all of these modules into one or morebundle
.
Webpack v4.0.0
To start, you don’t have to import a configuration file. However, WebPack is still highly configurable. There are four core concepts you need to understand before you begin:
- The entrance (
entry
) - Output (
output
) loader
- Plug-in (
plugins
)
This article aims to give a high level overview of these concepts and provide detailed use cases for specific concepts.
Let’s go over the basics
Webpack
Knowledge, if you are a master, then please ignore these directly to read….
-
The entrance
- The entry point indicates which module WebPack should use as a starting point for building its internal dependency graph. Once at the entry point, WebPack finds out which modules and libraries are (directly and indirectly) dependent on the entry point.
- Each dependency is then processed and finally output to called
bundles
We will discuss this process in detail in the next section. - Can be accessed through
webpack
Configuration in Configurationentry
Property to specify an entry point (or more entry points). The default value is./src
. -
Let’s look at the simplest example of an Entry configuration:
webpack.config.js module.exports = { entry: './path/to/my/entry/file.js' };Copy the code
-
The entry can be an object or a pure array
entry: { app: ['./src/index.js', './src/index.html'], vendor: ['react'] }, entry: ['./src/index.js', './src/index.html'],Copy the code
- One might say, how do you put the entrance
HTML
File because development mode hot update if not set entry forHTML
, so changedHTML
The content of the file, it’s not going to refresh the page, you have to refresh it manually, so this is the entryHTML
A document, a detail.
-
Exports (output)
- The Output attribute tells WebPack where to export the bundles it creates and how to name these files, with the default being./dist. Basically, the entire application structure is compiled into a folder in the output path you specify. You can configure these processes by specifying an output field in the configuration:
webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};Copy the code
In the example above, we use the output.filename and output.path attributes to tell the name of the Webpack bundle and where we want the bundle to emit. In case you’re wondering what the path module imported at the top of the code is, it’s a Node.js core module that manipulates file paths.
-
loader
-
- Loader enables Webpack to handle non-javascript files (WebPack itself only understands JavaScript). Loader can convert all types of files into valid modules that WebPack can handle, and then you can take advantage of WebPack’s packaging capabilities to process them.
- In essence, WebPack Loader converts all types of files into modules that the application’s dependency diagram (and ultimately its bundle) can reference directly.
- Note that loader can import any type of module (such as.css files), which is unique to WebPack and may not be supported by other packers or task executors. We think this language extension is necessary because it allows developers to create more accurate dependency diagrams.
- At a higher level, loader has two goals in the webpack configuration:
- The test property identifies the files or files that should be converted by the corresponding loader.
-
The use attribute indicates which loader should be used for conversion.
webpack.config.js const path = require('path'); const config = { output: { filename: 'my-first-webpack.bundle.js' }, module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] } }; module.exports = config;Copy the code
- Above configuration, on a separate
module
The rules object defines the rules property, which contains two required properties: test and use. This tells the Webpack compiler (compiler
) The following information:
- “Hey,
webpack
The compiler, when you encounter “inrequire()/import
Statement is resolved to'.txt'
Before you pack it, use itraw-loader
Switch.” - It’s important to remember that in
webpack
Definition in configurationloader
Is defined inmodule.rules
In, not rules. However, when the definition is wrongwebpack
Will give a serious warning. In order for you to benefit from this, if you don’t do it the right way,webpack
Will “give a serious warning” -
loader
There are more specific configuration properties that we haven’t mentioned yet. - Here is a quote from this author’s excellent article, handwritten one
loader
andplugin
Write a loader and plugin by hand
The climax came,webpack
Compiler principles, why learn to learn principles first? Because you should at least know what you’re writing about!
-
Webpack packaging principles
- Identification entry file
- Identify module dependencies layer by layer. (
Commonjs, amd
Or es6The import, webpack
It’s analyzed. To get code dependencies) -
webpack
All you do is analyze the code. Transform code, compile code, output code - The result is packaged code
- All of these are
webpack
Some of the basics for understandingwebpack
Is very helpful.
-
What is loader?
-
loader
Is a file loader, can load resource files, and perform some processing on these files, such as compilation, compression, and finally packaged together into the specified file - You can use more than one file
loader
.loader
The order of execution is the reverse of its own order, that is, the last oneloader
Execute first, number oneloader
Execute last. - The first to execute
loader
Receive source file contents as parameters, othersloader
Received from the previous executionloader
Returns the value of Last executedloader
This module will be returnedJavaScript
The source code - When using multiple
loader
If you want to modify a file while processing itoutputPath
Output directory, then please at the topOptions in the loader
-
-
What is a plugin?
-
- in
Webpack
Many events are broadcast during the runtime lifecycle,Plugin
You can listen for these events and change the output when appropriate through the API provided by Webpack.
- in
-
The plugin and loader
What is the difference between? - for
loader
, it is A converter to compile file A into file B. Here, the operation is the file, such as a.CSS or A.ess into B.CS, simple file conversion process -
plugin
It’s an extender, it’s enrichedwepack
In itself, for isloader
After the end,webpack
The whole process of packaging, which does not operate on files directly, works based on an event mechanism that listenswebpack
Some nodes in the packaging process perform a wide range of tasks.
-
The operation of the webpack
-
webpack
After it is started, it is executed first during the reading of the configurationnew MyPlugin(options)
Initialize a MyPlugin to get an example. Is called after the Compiler object has been initializedmyPlugin.apply(compiler)
Pass in the plug-in instancecompiler
Object. The plug-in instance is being retrievedcompiler
After the object can be passedcompiler.plugin
(Event name, callback function) onWebpack
An event broadcast. And can be accessed throughcompiler
Object to operatewebpack
- You might look at this and ask
compiler
Is what,compilation
Is what? -
Compiler
The Webpack object contains all configuration information for the Webpack environment, includingOptions, loaders, plugins
This information, which is instantiated when Webpack starts, is globally unique and can simply be understood asWebpack
Instance; -
Compilation
Object contains the current module resources, build resources, changing files, and so on. whenWebpack
Run in development mode whenever a file change is detected, a new oneCompilation
Will be created.Compilation
Object also provides many event callbacks for plug-ins to extend. throughCompilation
You can also read itCompiler
Object. -
Compiler
和Compilation
The difference lies in: -
Compiler
Represents the wholeWebpack
Lifecycle from startup to shutdown, whileCompilation
It just represents a new compilation.
-
-
Flow of events
-
webpack
throughTapable
To organize this complex production line. -
webpack
The event flow mechanism ensures the order of plug-ins and makes the whole system expand well. -
webpack
The event flow mechanism applies the observer pattern, andThe EventEmitter Node. Js
Very similar.
-
Let’s start the configuration of the development environment:
-
Entrance setting:
- Set up the APP, several entry files, which will eventually be split into several
chunk
- Configure in the entry
vendor
, you cancode spliting
And finally extract these common reusable codes into onechunk
Pack them separately - To be in development mode
HMTL
Files are also hot updated and need to be addedindex.html
Is the entry file
- Set up the APP, several entry files, which will eventually be split into several
Entry: {app: ['./ SRC /index.js', './ SRC /index.html'], vendor: ['react'] // Redux react-redux better scrollCopy the code
-
The output export
-
webpack
Based on theNode.js
The environment is running and can be usedNode.js
theAPI
.path
The moduleresolve
methods - The output of the
JS
File, joincontenthash
Flag to allow the browser to cache files between versions.
-
output: { filename: '[name].[contenthash:8].js', path: resolve(__dirname, '.. /dist') },Copy the code
-
mode: 'development'
Mode selection, here directly set to development mode, start from development mode. -
Add config to resolve all file suffixes without js JSX JSON
resolve: { extensions: [".js", ".json", ".jsx"] }Copy the code
-
Add plugin hot update plugin and HTMl-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin') const webpack = require('webpack') new HtmlWebpackPlugin({ template: './src/index.html' }), new webpack.HotModuleReplacementPlugin(),Copy the code
-
Add Babel-Loader and Babel Preset, which parses JSX ES6 syntax
-
@babel/preset-react
parsingJSX grammar
-
@babel/preset-env
parsinges6
grammar -
@babel/plugin-syntax-dynamic-import
parsingreact-loadable
theimport
Load on demand, attachedcode spliting
function
-
{
test: /\.(js|jsx)$/,
use:
{
loader: 'babel-loader',
options: {
presets: ["@babel/preset-react", ["@babel/preset-env", { "modules": false }]],
plugins: ["@babel/plugin-syntax-dynamic-import"]
},
}
},
Copy the code
-
React
On demand, with code splitting, each on demand component is packaged into a separate file
import React from 'react' import loadable from 'react-loadable' import Loading from '.. /loading' const LoadableComponent = loadable({ loader: () => import('.. /Test/index.jsx'), loading: Loading, }); Class Assets extends React.Component {render() {return (<div> <div> this is about to load on demand </div> </div>)}} class Assets extends React.Component {render() {return (<div> <div>)}} export default AssetsCopy the code
- join
html-loader
identifyhtml
file
{
test: /\.(html)$/,
loader: 'html-loader'
}Copy the code
- join
eslint-loader
{
enforce:'pre',
test:/\.js$/,
exclude:/node_modules/,
include:resolve(__dirname,'/src/js'),
loader:'eslint-loader'
}Copy the code
- The development mode termination code is shown below
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin') const webpack = require('webpack') const WorkboxPlugin = require('workbox-webpack-plugin') module.exports = { entry: { app: ['./src/index.js', './src/index.html'], vendor: ['react', ] }, output: { filename: '[name].[hash:8].js', path: resolve(__dirname, '.. /build') }, module: { rules: [ { enforce:'pre', test:/\.js$/, exclude:/node_modules/, include:resolve(__dirname,'/src/js'), loader:'eslint-loader' }, { oneOf: [{ test: /\.(html)$/, loader: 'html-loader' }, { test: /\.(js|jsx)$/, use: { loader: 'babel-loader', options: { presets: ["@babel/preset-react", ["@babel/preset-env", { "modules": false }]], plugins: ["@babel/plugin-syntax-dynamic-import"] }, } }, { test: /\.(less)$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true, localIdentName: '[local]--[hash:base64:5]' } }, { loader: 'less-loader' } ] }, { test: /\.(jpg|jpeg|bmp|svg|png|webp|gif)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[name].[hash:8].[ext]', } }, { exclude: /\.(js|json|less|css|jsx)$/, loader: 'file-loader', options: { outputPath: 'media/', name: '[name].[hash].[ext]' } } ] }] }, plugins: [ new HtmlWebpackPlugin({ template: ' '. / SRC/index. HTML}), new webpack. HotModuleReplacementPlugin (), new webpack. NamedModulesPlugin (), / / packaging when can see the file name of the plugin, mode: 'development', devServer: { contentBase: '.. /build', open: true, port: 3000, hot: true }, resolve: { extensions: [".js", ".json", ".jsx"] } }Copy the code
Must knowwebpack
Hot update principle:
-
Hot updates to Webpack are also known as Hot Module Replacement, or HMR. This mechanism allows you to replace the old module with the new one without refreshing the browser.
-
The first thing to know is that both the server and client side do the processing
- Step one, in
The watch webpack
In this mode, a file in the file system is modified.webpack
Listen for file changes, recompile and package the module according to the configuration file, and pass the packaged code through a simpleJavaScript
Objects are stored in memory. - The second step is to
webpack-dev-server
和webpack
Interface interaction between, and in this step, mainlydev-server
The middlewareWebpack - dev - middleware and webpack
The interaction between,webpack-dev-middleware
callwebpack
Exposed apis monitor code changes and tellwebpack
Package the code into memory. - The third step is to
webpack-dev-server
A monitoring of file changes, which, unlike the first step, does not monitor code changes for repackaging. When we configure it in the configuration filedevServer.watchContentBase
When true, the Server listens for changes in the static files in these configuration folders and tells the browser to live reload the application. Notice that this is browser refresh, and HMR are two different things. - Step four is also
webpack-dev-server
This step is mainly through sockJS (webpack-dev-server dependency) to establish a websocket long connection between the browser side and the server side, webpack compilation and packaging of each stage of the state information to inform the browser side, It also includes information that the Server listens for static file changes in step 3. The browser performs different operations based on these socket messages. Of course, the most important information passed by the server is the hash value of the new module, and the subsequent steps use this hash value to perform module hot replacement. -
webpack-dev-server/client
The end cannot request the updated code, nor does it perform the hot module operation, handing the work back to the endWebpack webpack/hot/dev server. -
Work is based onwebpack-dev-server/client
The messages that were sent to it anddev-server
Configuration determines whether to refresh the browser or hot update the module. Of course, if you just refresh the browser, there are no further steps. -
HotModuleReplacement.runtime
Is the backbone of the client HMR, which receives the new module passed to it in the previous stephash
Value, it passesJsonpMainTemplate.runtime
Send an Ajax request to the server, and the server returns onejson
thejson
Contains the hash values of all modules to be updated. After obtaining the updated list, the module will request jSONP again to get the latest module code. These are steps 7, 8 and 9 in the figure above. - Step 10 is the key step that determines the success of HMR. In this step,
HotModulePlugin
The old and new modules will be compared to decide whether to update the modules. After the decision is made to update the modules, the dependencies between the modules will be checked and the dependencies between the modules will be updated at the same time. - The last step, when
HMR
After failure, fall back tolive reload
Action, that is, a browser refresh to get the latest packaging code. - Reference article Webpack interview question – Tencent cloud
- Step one, in
Officially start production:
-
Join the WorkboxPlugin, PWA’s plugin
-
pwa
This technology is a bit of a work in progress, with its life cycle and the side effects of hot updates in browsers. You can refer to Baidulavas
Framework development history ~
-
const WorkboxPlugin = require('workbox-webpack-plugin') new WorkboxPlugin.GenerateSW({ clientsClaim: ImportWorkboxFrom: 'local', include: [/\.js$/, /\.css$/, /\.html$/,/\.jpg/,/\.jpeg/,/\.svg/,/\.webp/,/\.png/], }),Copy the code
- Add each time the package output file is emptied of the last package file plug-in
const CleanWebpackPlugin = require('clean-webpack-plugin')
new CleanWebpackPlugin()Copy the code
- join
code spliting
The code segment
Optimization: {runtimeChunk:true, // If this is set to true, a chunk is a file, and a chunk is a chunk with chunks, CSS images, etc. 'all' // chunk of default entry will not be split, set to 'all', can be split, an entry 'JS', // package to generate a separate file}}Copy the code
- Add separate extraction
CSS
Of the fileloader
And plug-ins
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
{
test: /\.(less)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader', options: {
modules: true,
localIdentName: '[local]--[hash:base64:5]'
}
},
{loader:'postcss-loader'},
{ loader: 'less-loader' }
]
}
new MiniCssExtractPlugin({
filename:'[name].[contenthash:8].css'
}),
Copy the code
- Join the compression
css
The plug-in
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
new OptimizeCssAssetsWebpackPlugin({
cssProcessPluginOptions:{
preset:['default',{discardComments: {removeAll:true} }]
}
}),Copy the code
- kill
html
Some useless code
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
}),Copy the code
- Add image compression
{ test: /\.(jpg|jpeg|bmp|svg|png|webp|gif)$/, use:[ {loader: 'url-loader', options: { limit: 8 * 1024, name: '[name].[hash:8].[ext]', outputPath:'/img' }}, { loader: 'img-loader', options: { plugins: [ require('imagemin-gifsicle')({ interlaced: false }), require('imagemin-mozjpeg')({ progressive: true, arithmetic: False}), require('imagemin-pngquant')({Floyd: 0.5, speed: 2}), require('imagemin-svgo')({plugins: [{removeTitle: true }, { convertPathData: false } ] }) ] } } ] }Copy the code
- join
file-loader
Package some files and export them to a fixed directory
{
exclude: /\.(js|json|less|css|jsx)$/,
loader: 'file-loader',
options: {
outputPath: 'media/',
name: '[name].[contenthash:8].[ext]'
}
}
Copy the code
There are some notes may not be detailed, the code is their own little bit of writing, tried, certainly no problem
- Required dependency
{" name ":" webpack ", "version" : "1.0.0", "main" : "index. Js", "license" : "MIT", "dependencies" : {" @ Babel/core ": "^ 7.4.4 @", "Babel/preset - env" : "^ 7.4.4", "@ Babel/preset - react" : "^ 7.0.0", "autoprefixer" : "^ 9.5.1", "Babel - loader" : "^ 8.0.5 clean - webpack -", "plugins" : "^ 2.0.2", "CSS - loader" : "^ 2.1.1", "eslint" : "^ 5.16.0", "eslint - loader" : "^ 2.1.2 file -", "loader" : "^ 3.0.1", "HTML - loader" : "^ 0.5.5", "HTML - webpack - plugin" : "^ 3.2.0", "imagemin" : "^ 6.1.0 imagemin - gifsicle", "" :" ^ the 6.0.1 ", "imagemin - mozjpeg" : "^ 8.0.0", "imagemin - pngquant" : "^ 7.0.0", "imagemin - svgo" : "^ 7.0.0", "img - loader" : "^ 3.0.1", "less" : "^ 3.9.0", "less - loader" : "^ 5.0.0", "mini - CSS - extract - the plugin" : "^ 0.6.0", "optimize - CSS - assets - webpack - plugin" : "^ 5.0.1", "postcss - loader" : "^ 3.0.0", "react" : "^ 16.8.6", "the react - dom" : "^ 16.8.6", "the react - loadable" : "^ 5.5.0", "the react - redux" : "^ 7.0.3", "style - loader" : "^ 0.23.1", "url - loader" : "^ 1.1.2 webpack", ""," ^ 4.30.0 ", "webpack - cli" : "^ 3.3.2 rainfall distribution on 10-12", "webpack - dev - server" : "^ 3.3.1", "workbox - webpack - plugin" : "^ 4.3.1"}, "scripts" : {" start ":" webpack dev - server -- config. / config/webpack. Dev. Js ", "dev" : "webpack-dev-server --config ./config/webpack.dev.js", "build": "Webpack --config./config/webpack.prod.js"}, "devDependencies": {"@babel/plugin-syntax-dynamic-import": "^7.2.0"}Copy the code