Webpack catalog
- The core configuration of webpack5
- Webpack5 modularity principle
- Webpackage 5 with Babel/ESlint/ browser compatibility
- Webpack5 performance optimization
- Webpack5 Loader and Plugin implementation
- Webpack5 core source code analysis
Babel usage
We rarely touch Babel directly in real development, but Babel is essential for front-end development. Babel is a toolchain that, like PostCSS, converts post-ECMAScript syntax code to ES5 code, including syntax conversions, source conversions, and Polyfill implementations.
Babel core installation
If we want to install @babel/cli on the command line, install NPM install @babel/core @babel/cli. NPM install @babel/preset-env -d if you want to use Babel, you need to install Bable. NPM install @babel/preset-env -d
Write a main.js file
Execute the command
npx babel src --out-dir dist --presets=@babel/preset-env
Copy the code
Generate results
You can see that the output file has been converted to ES5 syntax for us.
babel-loader
NPM install babel-loader -d to configure Babel. Configuration is as follows
{
test: /\.(j|t)sx? $/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env', {
targets: 'last 2 version' // Configure the targets attribute to override browserslist. Browserslist is recommended}]}}Copy the code
Babel configuration file
In addition to configuring the default Babel plug-in in the loader, the general situation is to extract a separate Babel configuration file
- Json (or.js,.cjs,.mjs) files
- Json (or. Babelrc,.js,.cjs,.mjs) files
Json /js is recommended. Let’s create a new babel.config.json
// babel.config.json
{
"presets": [["@babel/preset-env"]]}Copy the code
Polyfill
Now let’s change main.js, use a Promise Api, and repackage it
// main.js
const a= '123'
const fn = Promise.resolve(3)
fn.then(res= > {
console.log(res)
})
Copy the code
Now that you can see that the packaging doesn’t help us transform promises, it’s possible that promises won’t be supported on older browsers or on older versions. So we come up with a Polyfill thing that uses some syntactic new features (Promise, Generator, Symbol, etc., and instance methods array.prototype.includes, etc.) that will fill us in. The idea is to transform these apis and implement these new features using syntax apis that older browsers know. So how do we use it.
Previously we did this by installing the @babel/ Polyfill library, which we introduced in between at the top of the entry file. We don’t use it anymore. After Babel7.4.0, core-js and Regenerator-Runtime dependencies were introduced to provide polyfill. Install NPM install core-js regenerator-Runtime. Additional attributes need to be added after @babel/preset-env
useBuiltIns
What is the way to use polyfill, which has three valuesFalse, Usage, entryfalse
: Do not use any polyfill related codeusage
: Any polyfills you need in your code are automatically referenced to the relevant API(recommended)entry
: Which polyfills are required in the code, you need to add in the entryimport “core-js/stable”; import “regenerator-runtime/runtime”;The volume will go up
corejs
Set:corejs3.x is the most commonly used version- In addition, Corejs can set whether features in the proposal phase are supported or not
- Set the attributes of the proposals to true
The babel.config.json configuration is shown below
// babel.config.json
{
"presets": [["@babel/preset-env", {
"useBuiltIns": "usage"."corejs": 3}}]]Copy the code
Plugin-transform-runtime
Except that polyfill is global, so if we use Babel Polyfill when we’re writing our library, we might contaminate our global code. The plugin @babel/ plugin-transform-Runtime is recommended for polyfill. Install NPM install@babel /plugin-transform-runtime -d Configuration is as follows
// babel.config.json
{
"presets": [["@babel/preset-env"]],"plugins": [["@babel/plugin-transform-runtime", {
"corejs": 3}}]]Copy the code
NPM install — save@babel /runtime-corejs3
Jsx support
NPM install @babel/ preth-react-d when writing React, JSX syntax will be used, Babel official provides JSX preset @babel/ preth-react, NPM install @babel/ preth-react-d, as shown below
// babel.config.json
{
"presets": [["@babel/preset-env", {
"useBuiltIns": "usage"."corejs": 3
}],
["@babel/preset-react"]]}Copy the code
Typescript support
We will also use TypeScript for development in our projects, and TypeScript code needs to be converted to JavaScript code, as we used to use TS-Loader to process TS files. But Babel also provides @babel/preset-typescript. So what’s the difference between these two? Let’s use them separately.
ts-loader
NPM install ts-loader -d
{
test: /\.(j|t)sx? $/,
exclude: /node_modules/,
use: [
'ts-loader']}Copy the code
We’ll start with TSC –init, because when I download ts-loader I also install typescrit by default. Now initialize the tsconfig.json file and change main.js to main.ts
// main.ts
const a: string = '123'
const fn = Promise.resolve(3)
fn.then(res => {
console.log(res)
})
Copy the code
After repackaging, we found that the TS-Loader did not help us achieve polyfill
@babel/preset-typescript
Now let’s use @babel/preset-typescript. Install NPM install @babel/preset-typescript -d as follows
// webpack
{
test: /\.(j|t)sx? $/,
exclude: /node_modules/,
use: [
'babel-loader']}Copy the code
// babel.config.json
{
"presets": [["@babel/preset-env", {
"useBuiltIns": "usage"."corejs": 3
}],
["@babel/preset-react"],
["@babel/preset-typescript"]]}Copy the code
Now try repacking
Now we can see that polyfill has been provided for us
The difference between TS-Loader and @babel/preset-typescript
So should we choose TS-Loader or Babel-Loader in development? Let’s distinguish between the two
- ts-loader(TypeScript Compiler)
- To compile TypeScript directly, you can only convert TS to JS
- If we also want to add a corresponding polyfill in the process, then ts-Loader is powerless
- We need Babel to complete the filling function of polyfill
- babel-loader(Babel)
- To compile TypeScript directly, you can convert TS to JS, and you can polyfill
- However, babel-Loader does not detect type errors during compilation
So how do we do polyfill and provide type error detection? First of all, we definitely want to use Babel’s default. We can add a command to the script of package.json
"script" {
"ts-check": "tsc --noEmit"
}
Copy the code
When we perform at compile time once the command, but the individual is recommended to use a ForkTsCheckerWebpackPlugin plug-in, it can provide type error detection in developing and building environment, NPM install fork-ts-checker-webpack-plugin -d We can configure it as follows
// webpack
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
/ /...
{
plugins: [
/ /...
new ForkTsCheckerWebpackPlugin({
async: false,]}})Copy the code
So in our solution is to compile ts file @ Babel/preset – typescript and ForkTsCheckerWebpackPlugin the combination of the two plug-ins.
How Babel builds
We use a graph to see the entire process of compiling Babel
What the Babel compiler does is convert our source code into another piece of code that the browser can recognize directly. Workflow summary:
- Parsing
- Transformation phase
- Code Generation
ESlint configuration
ESLint is a static code analysis tool that helps us establish consistent team code specifications in projects, maintain correct and consistent code styles, and improve code readability and maintainability. And ESLint’s rules are configurable, so you can customize your own rules. Install ESlint, NPM install ESlint -d
Now let’s configure our ESLint rule, we’ll initialize ESLint first
npx eslint --init
Copy the code
Generate the.eslintrc.js file
This section describes the main properties of the configuration file
env
: running environment, such as browser, and we will use es2021(corresponding ecmaVersion is 12) syntaxextends
: Can extend the current configuration to inherit configuration information from other strings or arrays (multiple)parserOptions
: You can specify the version of ESMAScript and the type of sourceTypeparser
The default is Espree (also a JS Parser for ESLint), and if we need to compile other things like TypeScript, we need to specify the interpreterplugins
: Specifies the plug-in we are usingrules
: User-defined rules
The corresponding rules can be found on ESlint’s Official website
Now let’s test it with a command-line tool, modifying the main.js file
const a= '123'
const fn = () = > {
return a
}
console.log(fn(a))
Copy the code
Run the eslint command
npx eslint ./src/main.js
Copy the code
We can see that the command tells us that the string needs to use single quotes, and it tells us that we can fix it using –fix. In addition to checking the code specification through the command, we can also check it through the vscode plug-in
VSCode ESlint
We searched for ESlint in the plugin store, as shown in the image below
It checks against the.eslintrc.js configuration file of the current directory. If it doesn’t have that configuration file, it has a default configuration specification. Now looking at our main.js file, the editor has helped us wave out the irregularities
ESlint Loader
Eslint-loader: Eslint-loader: Eslint-loader: Eslint-loader: Eslint-loader: Eslint-loader: Eslint-loader: Eslint-loader Install NPM install eslint-loader -d
{
test: /\.(j|t)sx? $/,
exclude: /node_modules/,
use: [
'babel-loader'.'eslint-loader']}Copy the code
Auto repair save
ESLint will help you with errors (or warnings), but it won’t help you with automatic fixes; you’ll need to manually add the –fix parameter
eslint src --fix
Copy the code
Prettier in development, where we want to fix the problem when the file is saved, prettier could be used as an alternative tool. Prettier is searched for in the VSCode plugin store
However, it is not very popular to use this plug-in in real projects, and this habit may vary from person to person.
Problems encountered
TypeError: Cannot read property ‘getFormatter’ of undefined TypeError: Cannot read property ‘getFormatter’ of undefined TypeError: Cannot read property ‘getFormatter’ of undefined “^ 8.11.0 eslint -“, “loader” : “^ 4.0.2”,
After going through the debugger, I found that the esLint-Loader getOptions. Js references the ESLint CLIEngine
But the CLIEngine export is undefined, so I went to check eslint library reference by default. / lib/API. Js, found no CLIEngine derived.
Eslint /lib/cli-engine/index.js Eslint /lib/cli-engine/index.js in eslint-loader options
It says that we cannot export modules in ESLint through this path. I looked at esLint’s package.json and found that it imposes export restrictions
So we can configure it this way
// webpack
{
test: /\.(j|t)sx? $/,
exclude: /node_modules/,
use: [
'babel-loader',
{
loader: 'eslint-loader'.options: {
eslintPath: 'eslint/cli-engine'}}}]Copy the code
Exports of package.json in esLint add “./cli-engine”: “./lib/cli-engine/index.js”
Now let’s repack
As you can see, it’s working, but since we changed it to include esLint files in node_module, this was never a good idea, so we ended up deleting the original ESLint and lowering the ESLint version to 7.32.0. After installing it, repack it and it’s all ok now.
Browser compatibility
Browserslist
By compatibility, I mean features supported by different browsers: For example, the compatibility between CSS features and JS syntax, while we use Chrome, Safari, IE, Edge, Chrome for Android, UC Browser, QQ Browser and so on in the market. You can usually see this information in package.json in some scaffolding
> 1%
last 2 versions
not dead
Copy the code
> 1% means more browsers than the market share. The browser versions and market share can be found at caniuse.com/usage-table… View, as shown below
And we need to be compatible with browsers that are more than 1%, so we need to use Browserslist, which is a tool that shares the configuration of the target browser for the current condition, and when we use Browserslist to configure the conditions that we need to be compatible with, We will use the following compatibility tools to help us with CSS and JS compatibility.
- Autoprefixer
- Babel
- postcss-preset-env
- eslint-plugin-compat
- stylelint-no-unsupported-browser-features
- postcss-normalize
- obsolete-webpack-plugin
Browserlist is automatically installed when webPack is installed. You can use the browserslist command to view the list of target browsers.
npx browserslist ">1%, last 2 version, not dead"
Copy the code
Note: browserslist looks for the. Browserslistrc configuration file if it is not followed by a condition, otherwise the default condition is used.
These are the target browsers that meet our criteria and need to be compatible.
There are two ways to configure Browserslist:
- Package. The json configuration
- independent
.browserslistrc
Configuration file
Package. The json configuration
{
/ /...
"browserslist": [
"1%" >."last 2 version"."not dead"]}Copy the code
Browserlistrc file configuration, in the project directory to create a. Browserslistrc file
Note: Conditions are union when comma or space or OR is used between them. Use and as the intersection between conditions. Not is not included when not is used between conditions.
See Github Address for browserslist configuration details
Postcss
After confirming the target browser that needs to be compatible, we need to use tools to do compatibility processing. First, we need to introduce PostCSS.
PostCSS is a JavaScript style conversion tool, this tool can help us to do some CSS conversion and adaptation, such as automatically add browser prefix, CSS style reset, but to achieve these tools, we need to use PostCSS corresponding plug-in, These plug-ins are the compatibility tools described above.
You can use the command line to test the autoprefixer plug-in under the Postcss tool. You need to install postCSS, postCSS -cli, and run NPM intall postcss postCSS -cli -d to install postcss.
Using terminal commands requires the postCSS-CLI dependency package, and converting requires postCSS.
After that, we need to download the plug-in autoprefixer for compatibility processing. Postcss needs to specify a plug-in for processing, NPM Intall Autoprefixer -d. After installation, we can use the terminal command line to test.
npx postcss --use autoprefixer -o result.css ./src/css/index.css
Copy the code
After executing the command
You can see that the output result.css file has automatically added compatibility code to our style properties. But in a real project it is impossible to use commands to do the transformation, so we need a loader to process the style files, and WebPack uses postCSS-loader to do that. Install NPM install postCSs-loader -d.
Add postCSs-loader to webpack.config.js.
{{test: /.css$/i,
use: [
'style-loader'.'css-loader',
{
loader: 'postcss-loader'.options: {
postcssOptions: {
plugins: [
'autoprefixer' // Require ('autoprefixer')}}}]}}Copy the code
But we use postCSS-loader not only in CSS files, but also in other files such as preprocessor less. This becomes tedious when we repeatedly write postCSs-loader. At this point we can extract the postcss.config.js file and put the configuration in that file, whereas the Webpack configuration becomes
{
rules: [{test: /.css$/i,
use: [
'style-loader'.'css-loader'.'postcss-loader'] {},test: /.less$/i,
use: [
'style-loader'.'css-loader'.'postcss-loader'.'less-loader']]}}Copy the code
Then separate out the postcss.config.js file
Postcss is almost ready now, and autoprefixer is no longer in use, we recommend postCSs-preset -env more. This plugin includes autoprefixer and can preset some modern CSS features, Convert to CSS that most browsers know, and add the required polyfills depending on the target browser or runtime environment. Install NPM install postCSs-env -d. Modify the postcss.config.js file
module.exports = {
plugins: [
'postcss-preset-env']}Copy the code
For example, the style attribute color: #28f2d334, when set to 8 bits, some browsers will recognize it and some won’t. Postcss-preset -env will help us with compatibility processing
After repackaging the build, you can see that the color attribute value has been converted to RGBA format, and the prefix compatibility processing for the previous attribute is done.
Postcss-loader and CSS-loader do not execute the postCSs-loader again when we import other CSS files from the @import CSS file. So we need to add configuration in CSS-Loader
{
rules: [{test: /.css$/i,
use: [
'style-loader',
{
loader: 'css-loader'.options: {
importLoaders: 1 // Importing CSS from CSS does not start with postCSs-loader but with CSS-loader conversion, so this configuration ensures that loader conversion starts one layer up}},'postcss-loader'] {},test: /.less$/i,
use: [
'style-loader',
{
loader: 'css-loader'.options: {
importLoaders: 2 // Importing CSS from CSS does not start with postCSs-loader but with CSS-loader conversion, so this configuration ensures that loader conversion starts one layer up}},'postcss-loader'.'less-loader']]}}Copy the code