What exactly is Webpack?
In essence, Webpack is a static Module bundler for modern JavaScript applications. As WebPack processes the application, it internally creates a Dependency graph that maps to each module required by the project, and then generates all those dependencies into one or more bundles.
Note: Webpack is not a JS compiler, but a module packaging tool (not only a JS module packaging tool, but also supports CSS, images, etc.);
JS specifications supported by Webpack include ES Moudule, CommonJS, CMD, AMD, etc.Copy the code
A few examples of the above specifications:
- ES2015 import statement (ES6 syntax)
- CommonJS require() ==> asynchronously introduce, require.resolve() ==> synchronously obtain the module ID
- AMD DEFINE and require statements, define export cannot be called in asynchronous functions
- @import statement in CSS /sass/ LESS files.
- Style (url (…). ) or an image URL in an HTML file
Two ways to speed up WebPack packaging:
(1) Keep node.js versions up to date; (2) Keep WebPack versions up to dateCopy the code
This is because the new version of WebPack will take advantage of Node’s new features to speed up its packaging.
The correct way to install WebPack
There are two normal webPack installation methods: global installation and local project installation
(1) Use the following command line to install webPack globally
npm install webpack webpack-cli -g
Copy the code
(2) Use the following command line to install the local project
npm install webpack webpack-cli -D
Copy the code
The above commands are equivalent to:
npm install webpack webpack-cli --save-dev
Copy the code
When selecting the Webpack version, use NPM install webpack@version -d to install so that you can switch between projects to use the Webpack version.
Note: When we have other projects that need to use Webpack3 or older versions, we will get an error if we use the current webpack command to perform packaging. This is because the current webpack command uses the webpack command under the global installation. The solution is to uninstall the original global installation of Webpack and webpack-CLI and install in local project mode (2).
Check: How to check whether the installation is successful?
When we use webpack -v, we will be prompted to say that there is no webpack globally and we can install webpack-CLI scaffolding to use it
One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:
- webpack-cli (https://github.com/webpack/webpack-cli)
The original webpack full-featured CLI.
We will use "npm" to install the CLI via "npm install -D".
Do you want to install 'webpack-cli' (yes/no):
Copy the code
To use the webpack command for the current project, add NPX as follows:
npx webpack -v
npx webpack-cli -v
Copy the code
How to use webPack configuration files easily?
Webpack has encapsulated a lot of default configurations for us. When we do not manually configure the configuration, we will use the default configuration. However, in a complex project, we usually want to change the default configuration of WebPack using files configured according to our requirements.
(1) Create the default configuration file webpack.config.js for WebPack
(2) Modify the default configuration of Webpack, the code is as follows:
const path = require('path'); Module.exports = {// configure the webpack package entry: './index.js', // configure the webpack package output: {// configure the package name filename: Resolve (__dirname, 'bundle')}}Copy the code
(3) Run the command to pack the package
npx webpack
Copy the code
(4) If we do not want to use webpack’s default configuration file name webpack.config.js, for example, we can change it to webpackconfig. js, then an error will be reported if you execute the package command, because Webpack does not recognize your current configuration file. Instead of using the original default configuration file, we need to make webPack use your current configuration file as the current configuration using the following command.
npx webpack --config webpackConfig.js
Copy the code
NPM scripts: NPM scripts: NPM scripts: NPM scripts: NPM scripts:
"scripts": {
"bundle": "webpack"
}
Copy the code
Then execute the following package command:
npm run bunlde
Copy the code
“Bundle “:” NPX webpack” :” NPX webpack” :” NPX webpack” :” NPX webpack” :” NPX webpack” :” NPX webpack”
This is because NPM scripts is configured as webpack. After executing the package command, it first looks for webpack in node_modules of the current project, and then goes up one level to global node_modules to find webpack.
There are three ways to use Webpack
(1) In the global context:
webpack index.js
Copy the code
(2) In the current project folder:
npx webpack index.js
Copy the code
(3) use webpack configuration file + NPM scripts to add package command:
npm run bundle
Copy the code
A question: What is the use of the original Webpack-CLI installation?
(1) Enable us to use webpack command directly from the command line
(2) in the local project folder, if the global does not install webpack, using webpack to find the global report you did not install webpack, and as long as you have installed webpack in the local project, using NPX webpack can find the local webpack command.
What is loader?
When we package, we introduce more than just js files. For example, it can be an image file:
var avator = require('./avator.jpg');
Copy the code
If we also execute the package command, we will be prompted with a package error, because Webpack itself only packages JS files under the default configuration, so when we want to package image files, we need to introduce the corresponding loader and configure webpack to support image packaging.
Webpack packs images with the help of file-loader configuration:
(1) Install file-loader in local project:
npm install file-loader -D
Copy the code
(2) use file-loader rule in webpack.config.js configuration:
Module: {rules: [{// matches files ending in.jpg test: /\.jpg$/, // Uses file-loader to package matched files. Use: {loader: 'file-loader'}}]}Copy the code
(3) After the configuration is complete, run the package command to package:
npm run bundle
Copy the code
In short, WebPack does not recognize static resources that are packaged other than JavaScript, and various Loaders are used to preprocess files that can be packaged for any static resources other than JavaScript.
Picture package package
Before we begin, take a look at the directory structure of our current files, as shown below:
import avator from './avator.jpg';
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
root.append(img);
Copy the code
Here, an img tag is created in index.js, and the packaged Avator image is assigned to the img SRC and mounted to root for display.
The next code in the index.html file is as follows:
<! DOCTYPE HTML > < HTML lang="en"> <head> <meta charset="UTF-8"> <title> </head> <body> <p id='root'></div> <script src='./.. /dist/bundle.js'></script> </body> </html>Copy the code
The above code looks ok, then execute the package command, no error is reported, everything seems ok, but when we open the index.html in the browser, we see this screen, as shown below:
The picture unexpectedly can not find, this is what reason ah?
img.src = avator; //6db51315be71c2bc73d1bc8663cc1ebc.jpg
Copy the code
This is because the img SRC attribute assigns the name and extension of the packaged image. In this case, index.html introduces bunlde.js in the bundle.js directory, just as index.html introduces bunlde.js in the SRC directory. When executing bundle.js, I went to SRC to find the packaged image, but I couldn’t find it. On the other hand! If the index.html is in the dist directory, the packaged image is also in that directory, so load it!
Solutions are as follows:
A:
Method 2:
Without changing the location of index. HTML, directly modify the code in the index.js file as follows:
import avator from './avator.jpg'; var root = document.getElementById("root"); var img = new Image(); img.src = "./.. /dist/"+avator; console.log("./.. /dist/"+avator) root.append(img);Copy the code
In this case, the image will be packaged in the dist directory, and the image will be displayed in the browser by assigning the image path from the dist directory to the img SRC property.
Using Loader to package static resources
file-loader
File-loader () : file loader () : file loader () : file loader () : file loader () : file loader (
(1) Install file-loader. The latest version 3.0.1 is installed directly, but the new version does not include the required dependencies, so it is later downgraded to version 2.0.0
NPM install [email protected] - DCopy the code
When used in combination with a placeholder, a common option
Placeholder name: '[name]_[hash].[ext]', outputPath: 'images/'}}Copy the code
Options:
OutputPath: indicates the output directory of the configured resource. EmitFile: indicates that only the public URL is returned but no file is generated. The default value is true and falseCopy the code
Placeholder: Placeholder
[name] : basic name of the resource [hash] : encryption rule for the configuration file name (default MD5 encryption) [ext] : extension of the resource [path] : path of the resource relative to contextCopy the code
url-loader
Url-loader is similar to file-loader. The basic configuration is as follows:
(1) Installation
npm install url-loader -D
Copy the code
(2) Quick use
Placeholder name: '[name]_[hash].[ext]', outputPath: 'images/', // 20KB limit: 20480 } }Copy the code
Options:
Fallback: When the file exceeds the limit, the corresponding loader will be used (default is file-loader). Fallback: When the file exceeds the limit, the corresponding loader will be used.Copy the code
The difference between url-loader and file-loader
Using url-loader is suitable for small image files (several KB), which can be directly embedded in the URL and loaded when the browser JS script is running without sending a request. However, if the image file is too large and the script is loaded too long, the first screen will be displayed for a long time.
File-loader is suitable for large image files to solve the problem of file reference path. After the file is packed, the corresponding image file is generated. When the HTML file is opened, the browser sends a request.
Packing static resources with Loader (Style section)
Basic style packaging process
Static resources supported by Webpack are not only images, but also CSS, Less, Scss and other style files. At this time, we need to use style-loader, CSS-loader, sas-loader to support Webpack packaging. Simple examples are as follows:
(1) create index. SCSS in SRC directory and write sass style as follows:
body { .avator { width: 150px; height: 150px; transform: translate(100, 100); }}Copy the code
(2) Import SCSS style from SRC directory index.js and add class to dom of corresponding image, code is as follows:
import avator from './avator.jpg'; import './index.scss' var root = document.getElementById("root"); var img = new Image(); img.src = avator; // Add avatorClass img.classlist. add('avator') to img; root.append(img);Copy the code
(3) Add the following configuration to the webpack.config.js file:
{test: /\. SCSS $/, use: [// execute 'style-loader', 'css-loader', 'sass-loader', 'postCSs-loader']}Copy the code
Note: The loader executes from bottom to top, or from right to left if written as a line
(4) We use transform in the style of sASS file. If the style attribute needs to support various browsers, the corresponding browser manufacturer prefix should be added, such as -webkit-, etc. At this time, we can use webpack postCSS-loader to automatically add the manufacturer prefix to us. Postcss-loader also needs to create its own configuration file postcss.config.js and add autoprefixer plugin as follows:
-
Install style-loader, CSS-loader, sass-loader, postCSs-loader, node-sass, autoprefixer:
npm install -D style-loader css-loader sass-loader postcss-loader node-sass autoprefixer Copy the code
-
Create the postcss.config.js file in the root directory and add the following code:
Module. exports = {plugins: [// import plugins require('autoprefixer')]}Copy the code
(5) Delete the images folder and bundle.js under Dist, execute the packaging command to complete the packaging, open the HTML file, run the browser, select the corresponding image element, and you can see that avator class is mounted on it, and add the manufacturer prefix beside transform.
The general process of execution
- Execute pack command
- Webpack matches to the SCSS style file
- Package with sass-Loader
- The packaged SCSS styles are forwarded to CSS-loader for translation
- The modified styles are handed to the PostCSS-Loader and the corresponding vendor prefixes are automatically added with the help of the Autoprefixer plug-in
- Prefixed styles are passed to the style-loader to be mounted to the style on the DOM
Nested SCSS style issues
We may import another SCSS style file in the SCSS style file. In this case, if the original execution order is followed, only the first SCSS file can be processed and translated, and the other one is not translated, i.e. postCSs-loader and sass-loader are executed only once. The solution is to let the two Loaders execute again.
Relevant file codes are modified as follows:
(1) Create avator. SCSS file in SRC directory, write code as follows:
body { .avator { width: 220px; height: 150px; }}Copy the code
(2) Import avator. SCSS into index. SCSS:
@import './avator.scss'; body { .avator { transform: translate(100px, 100px); }}Copy the code
(3) Webpack.config. js needs to be modified into the following code configuration:
{test: /\. SCSS $/, use: [// execute 'style-loader' from bottom to top, {loader: 'css-loader', options: {// Use the following two loaders to configure the number of loaders "csS-loader before @import resources" : 2 } }, 'sass-loader', 'postcss-loader' ] }Copy the code
How to use the modularity of CSS?
Createavator.js createAvator.js createAvator.js createAvator.js createAvator.js createAvator.js createAvator.js createAvator.js createAvator.js createAvator.js createAvator.js createAvator.js
import avator from './avator.jpg';
export default function () {
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
img.classList.add('avator');
root.append(img);
}
Copy the code
Add createAvator to index.js and call createAvator
import avator from './avator.jpg'; import createAvator from './createAvator'; import './index.scss'; CreateAvator (); var root = document.getElementById("root"); var img = new Image(); img.src = avator; img.classList.add('avator'); root.append(img);Copy the code
SCSS style is now a global style. How to solve this problem and make CSS styles modular?
(3) To make SCSS style support CSS module, you need to set the parameter module to true in csS-loader in webpack.config.js:
SCSS $/, use: [// Execute 'style-loader' from bottom to top, {loader: 'css-loader', options: {importLoaders: 2, // set csS-loader to support CSS modules Modules: true}}, 'sass-loader', 'postCSs-loader']}Copy the code
(4) Modify the way of introducing index. SCSS in index.js and introduce it in a modular way, the code is as follows:
import avator from './avator.jpg';
import createAvator from './createAvator';
import style from './index.scss';
createAvator();
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
img.classList.add(style.avator);
root.append(img);
Copy the code
Create avatars with createAvator instead of using index.scss. Create avatars with createAvator. Create createavator.js and import the SCSS module to createavator.js.
import avator from './avator.jpg'; Import style from './index.scss'; export default function () { var root = document.getElementById("root"); var img = new Image(); img.src = avator; Img. Classlist. add(style.avator); root.append(img); }Copy the code
How does WebPack package font files?
We may need to use the font style file in the actual project application, and WebPack also supports the packaging of the font style file we need for the project, the detailed steps are as follows:
(1) First add several ICONS to the project from iconfont Ali icon vector library, and then download the corresponding font style file to the local
(2) Create a font folder in the SRC directory, and download the font style files ending with eOT, SVG, TTF, and woff to the font folder
(3) Paste iconfot. CSS in index. SCSS and modify the import path. The code is as follows:
@font-face { font-family: "iconfont"; src: url('./font/iconfont.eot? t=1543245201565'); /* IE9*/ src: url('./font/iconfont.eot? T =1543245201565#iefix') format('embedded-opentype'), /* ie6-ie8 */ / T =1543245201565') format(' trueType '), /* Chrome, Firefox, Opera, Safari, Android, iOS 4.2+*/ url('./font/iconfont. SVG? t=1543245201565#iconfont') format('svg'); /* iOS 4.1- */Copy the code
(4) Import index. SCSS from index.js and create the corresponding font div as follows:
var root = document.getElementById('root'); import './index.scss'; Root. innerHTML = '<div class="iconfont icon-changjingguanli"></div>';Copy the code
(5) Add configuration to handle eOT, SVG, TTF ending file packaging in webpack.config.js, code is as follows:
{
test: /\.(eot|svg|ttf)$/,
use: {
loader: 'file-loader'
}
}
Copy the code
(6) Run the index.html package to see the font displayed
Use plugins to make packing faster
Html-webpack-plugin – Automatically creates HTML
When we were packing previously, we had to delete all but index. HTML in the dist directory every time, but could not delete the whole dist directly. Then, could we directly delete the dist directory every time before packaging, and automatically generate the index. HTML file that met our configuration after packaging?
This requires the use of webpack htmL-webpack-plugin, the basic steps are as follows:
(1) Install htML-webpack-plugin
npm install html-webpack-plugin -D
Copy the code
(2) add html-webpack-plugin to webpack.config.js file:
const HtmlWebPackPlugin = require('html-webpack-plugin');
Copy the code
(3) Add configuration to webpack.config.js:
New HtmlWebPackPlugin({// Create index.html template from index.html: 'SRC /index.html'})]Copy the code
Note: Webpack automatically adds index.html and introduces bundled bundle.js to script tags when we delete dist outright.
Plugins, like vue or React lifecycle functions, automatically do things for you when WebPack is running at a certain point.
Clean-webpack-plugin — Automatically deletes files before packaging
In the above operations, we manually deleted the files under Dist before packaging each time. Is there any good tool that can help us to automatically delete the dist folder and all the files under it before packaging?
The answer is definitely yes, we need to use the webpack third-party plugin namely clean-webpack-plugin, the specific steps are as follows:
(1) Install clean-webpack-plugin:
npm install clean-webpack-plugin -D
Copy the code
(2) add clean-webpack-plugin to webpack.config.js:
const CleanWebpackPlugin = require('clean-webpack-plugin');
Copy the code
(3) Configure plugins in webpack.config.js:
New HtmlWebPackPlugin({template: 'SRC /index.html'}), // create an instance and pass in the folder to remove new CleanWebpackPlugin(['dist'])]Copy the code
A few insights into SourceMap
SourceMap (SourceMap, SourceMap, SourceMap, SourceMap)
(1) Delete the index.js code from the SRC directory and add a line of code:
consles.log("hello world"); // There is an intentional console errorCopy the code
(2) Setting mode to development in webpack.config.js automatically opens sourceMap, so we manually turn it off:
Devtool: 'none',Copy the code
(3) After executing the package command and running index.html to open the console, errors will be reported in line 96 of the packaged main.js code. If we click main.js, errors will be entered in the packaged main.js code, but in practice, even if we modify the code in main.js, the packaging is still wrong again. This is because we are only modifying the packaged code, not the source file, so we want the console to give us an error message from the source file, so we use the SourcMap function:
Devtool: 'sourceMap ',Copy the code
(4) Perform the packaging again, the console can see the error message is in the source file index.js the first line of the misspelled console.
SourceMap is used to set up the mapping between the source code and the packaged code. It is mainly used in devtool. There are a lot of configuration parameters.Copy the code
- Source-map: a. Map file is generated to represent the mapping to source code, slowing down packaging
- Inline-source-map: the. Map file is no longer generated, but the mapping is stored as base64 in the data URL of the packaged file
- Cheap -inline-source-map: only care about the source code error, loader error, no longer prompt us which line error, but only accurate to the line, packaging speed is relatively fast
- Cheap -module-source-map: not only the source code error to manage, but also the loader, etc
- Eval: Outputs a short error message in the last line of a packed file
As above, arguments in devTool can be superimposed, usually as follows:
In development mode, Devtool uses cheap-module-eval-source-map
In production mode, devtool uses cheap-module-source-map
Use webapckDevServer to improve development efficiency
When we use Webpack, every time we modify the source code file, we have to execute the package command again, which is very inconvenient. Can WebPack listen to the source code changes and automatically help us package again?
The powerful WebPack gives us many ways to do this, but here are two:
(1) Directly configure it in scripts in package.json file, and execute NPM run watch:
"scripts": {
"watch": "webpack --watch"
},
Copy the code
(2) Use webpackDevServer
-
Webpack – dev – server installation
npm install webpack-dev-server -D Copy the code
-
Configure devServer in the webpack.config.js file:
DevServer: {// tell the server from which directory to provide content contentBase: './dist', // automatically start the browser to localhost:8080 page open: true}Copy the code
-
Json file, run NPM run start to start the service:
"scripts": { "bundle": "webpack", "watch": "webpack --watch", "start": "webpack-dev-server" } Copy the code
Note: Proxy forwarding can also be configured with webpackDevServer, for example:
module.exports = { //... devServer: { proxy: { '/api': 'http://localhost:3000' } } }; Copy the code
Above agent means when the request to the/API/XXX agent to request http://localhost:3000/api/xxx, this way make our front in mock data don’t need to use the proxy tools such as Charles.
Integration of WebPack Mini-Server with Express and Webpack-dev-Middleware
Webpack can also integrate small servers like webpackDevServer with webpack-dev-Middleware and Express.
(1) Packages and dependencies required to install the service:
npm install express webpack-dev-middleware -D Copy the code
(2) In the webpack.config.js file, configure the path to generate the new file, namely publicPath:
Output: {publicPath: '/', // configure the filename after the package filename: '[name].js', // configure the directory for storing the file after the package (absolute path) path: path.resolve(__dirname, 'dist') }Copy the code
(3) Configure scripts in package.json file:
"scripts": { "bundle": "webpack", "watch": "webpack --watch", "start": "webpack-dev-server", "server": "node server.js" } Copy the code
(4) Create server.js in the same directory as webpack.config.js and write the code as follows:
const express = require("express"); const webpack = require("webpack"); const webpackDevMiddleWare = require("webpack-dev-middleware"); Const config = require("./webpack.config"); Const complier = webpack(config); // Create a node web server based on express const app = express(); Use (webpackDevMiddleWare(complier, {// Configure the path to generate new files, use the corresponding path publicPath: config.output.publicPath })); App. listen(3000, ()=> {console.log("server is running"); })Copy the code
(5) Run NPM run server to start the service, and enter localhost:3000 in the browser to go to the page
Update HotModuleReplacementPlugin thermal module
In the development process, especially in the front-end development of some HTML and CSS style adjustments, we do not want to refresh the entire browser page, just want webpack to help us to cover the part of THE HTML and CSS code we modify, similar to partial refresh. Thermal module updates HotModuleReplacementPlugin can help us to solve this problem well, the specific implementation steps are as follows:
(1) In webpack.config.js file to configure the packaging processing of imported CSS files:
{test: /\.css$/, use: [// execute 'style-loader', 'css-loader', 'postCSs-loader']}Copy the code
(2) Configure hot update in webpack.config.js:
Const webpack = require('webpack'); const webpack = require('webpack'); ContentBase: './dist'; // Start the browser automatically and go to localhost:8080. True, port: 8080, // Enable hot module update hot: true, // Don't let Webpack refresh the HTML for us, but directly give us an error hotOnly: True} / / in the plugins created under the plugin instance new webpack. HotModuleReplacementPlugin ()Copy the code
(3) Create a style. CSS file in the SRC directory with the following code:
div:nth-of-type(odd) {
background: blue;
}
Copy the code
(4) create index.js under SRC as follows:
import './style.css'; var btn = document.createElement('button'); Btn. innerHTML = 'new '; document.body.appendChild(btn); btn.onclick = function() { var div = document.createElement('div'); div.innerHTML = 'item'; document.body.appendChild(div); }Copy the code
(5) Execute NPM run start to start the service, click the new button in the browser, and find that the div in odd rows is blue. We change the background color of style.css to green
div:nth-of-type(odd) {
background: green;
}
Copy the code
When saving, I returned to the browser and found that the number of items created was still there, and the color of the item also turned green, realizing the hot update of the CSS module.
Note: Sometimes we want to implement js module hot update, Webpack also has a corresponding solution, as shown in the following example:
Create counter. Js, number.js and number1.js under SRC:
// counter .js
function counter() {
var div = document.createElement('div');
div.setAttribute('id', 'counter');
div.innerHTML = 1;
div.onclick = function() {
div.innerHTML = parseInt(div.innerHTML, 10) + 1
}
document.body.appendChild(div);
}
export default counter;
// number.js
function number() {
var div = document.createElement('div');
div.setAttribute('id', 'number');
div.innerHTML = 4000;
document.body.appendChild(div);
}
export default number;
// number1.js
function number1() {
var div = document.createElement('div');
div.setAttribute('id', 'number1');
div.innerHTML = 1000;
document.body.appendChild(div);
}
export default number1;
Copy the code
(2) Add the following code to clear index.js:
import counter from './counter'; import number from './number'; import number1 from './number1'; counter(); number(); number1(); if(module.hot) { module.hot.accept('./number', () = > {/ / to remove the id selector for number document. The body. The removeChild (document. GetElementById (" number ")); // create div and set id to number number(); }) module.hot.accept('./number1', () => { document.body.removeChild(document.getElementById('number1')); number1(); })}Copy the code
(3) The hot update in webpack.config.js is configured to run the service directly. Open the browser and click on the counter a few times before changing the div.innerhtml value in number.js and number1.js. You can see that the number and number1 values on the page are going to change but the counter value is going to stay the same, it’s not going to go back to 0.
Use Babel for ES6 syntax under Webpack
Some ES6 syntaxes have replaced the old syntaxes, but some browsers are not compatible with the new ES6 syntaxes. Babel allows you to convert ES6 syntaxes into ES5 syntaxes for the browser to execute.
The steps for ES6 using Babel in Webpack are as follows:
(1) First write the ES6 code that needs to be translated in index.js:
const arr = [
new Promise(() => {}),
new Promise(() => {})
];
arr.map(item => {
console.log(item);
});
Copy the code
(2) Install babel-loader, @babel/core, @babel/preset-env, @babel/polyfill:
npm install babel-loader @babel/core @babel/preset-env @babel/polyfill -D
Copy the code
(3) Configure the webpack.config.js file:
// Configure {test: /\. Js $/, // exclude: /node_modules, loader: "babel-loader", options: {"presets": [["@babel/preset-env", {// Configure Babel /polyfill according to the variables and functions used by the business code, so that the file is smaller. UseBuiltIns: 'usage'}]]}}Copy the code
Note: The babel-loader here only Bridges the gap between WebPack and the Babel translator. We also need to tell WebPack about the rules and environment for compiling, so we need to configure the Presets above
@babel/polyfill should be imported into index.js to make up for some variables and functions in earlier versions of browsers:
// index.js // @babel/polyfill can make up for some of the variables and functions import "@babel/polyfill";Copy the code