Webpack runs in two ways

Install: NPM installWebPackwebpack -cli–save-dev

Method 1: Cli installation

Establish a webpack. Config. Js

const path = require('path');
module.exports = {
    entry:'./src/index.js'.output: {filename:'bundle.js'.// Package the resulting file
        path:path.resolve(__dirname,'dist') // Package to the dist directory}}Copy the code

Run the command:

"scripts": {
  "build": "webpack --config ./webpack.config.js"."dev": "webpack" // Do not write the configuration file. By default, the configuration file in the current working directory is found
}
Copy the code

Note: Wepback does not write configuration files and by default reads webpack.config.js from the current working directory

Mode 2: Node running mode

const path = require('path');
var webpack = require('webpack');
var options = {
  mode: 'development'.context: process.cwd(),
  entry: './src/index.js'.output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {},
  plugins: [
    new HtmlWebpackPlugin({
      template: './dist/index.html'.// Specify a template file
      filename: 'index.html'.// The output file name
      inject: false.hash: true.// To avoid caching, you can add hash values to the end of the output resource}),].devServer: {
    port: 8080}}var compiler = webpack(options);
Copy the code

The command line is suitable for a project, and Node runs as a scaffold.

Webpack-dev-server (Hot Update)

Purpose: Configures the development server, which can be packaged in memory during implementation and automatically starts the service

npm installwebpack-dev-server–save-dev

Common Usage

Cli mode:

"scripts": {
    "build": "webpack --env.production --config ./build/webpack.base"."dev": "webpack-dev-server --env.development --config ./build/webpack.base"
}
Copy the code

Nodejs run

 var server = new WebpackDevServer(compiler);
 server.listen(8080);
Copy the code

Common configurations:

devServer: {
      contentBase: "./build/".// Listen for code changes to automatically commit and refresh the page
      host: '0.0. 0. 0',
      port: 8080,
      open:'true',
      disableHostCheck: true,
      proxy: { // Configure the proxy
        '/web/webApi': {
          target: proxyUrl,
          secure: false,
          changeOrigin: true,
          pathRewrite: {'/web/wx' : ''}
        }
      }
}
Copy the code

HMR (Hot module replacement)

Start the HMR

 devServer: {
	contentBase: "./dist".open: true.hot:true.HotOnly :true hotOnly: hotOnly:true
},
Copy the code

Plugins add

 plugins: [
    new webpack.HotModuleReplacementPlugin()
],
Copy the code

Note: CSS stripping does not take effect after HMR is enabled, contenthash, and Chunkhash are not supported

Handle js module HMR

You need to use module.hot.accept to observe module updates to update

if (module.hot) {
  module.hot.accept("./b".function() {
    document.body.removeChild(document.getElementById("number"));
    number();
  });
}
Copy the code
  • Sensations don’t matter much if they can’t be processed automatically.

Html-webpack-plugin (Page Development)

Single page packaging

const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins:[
    new HtmlWebpackPlugin({
        filename:'index.html', // The name of the packaged filetemplate:path.resolve(__dirname,'.. /public/index.html'), hash:true.// Add a hash stamp to the end of the reference resource
        minify:{
            removeAttributeQuotes:true // Delete attribute double quotes}})]Copy the code

Note: This method imports all of entry’s JS files into the HTML.

Multi-page packaging

Multiple entries You need to configure multiple entries

entry:{
    jquery: ['jquery']./ / packaging jquery
    entry1:path.resolve(__dirname,'.. /src/entry-1.js'),
    entry2:path.resolve(__dirname,'.. /src/entry-2.js')},output: {filename:'[name].js'.path:path.resolve(__dirname,'.. /dist')},Copy the code

Generate multiple Html files

new HtmlWebpackPlugin({
    filename:'index.html'.template:path.resolve(__dirname,'.. /public/template.html'),
    hash:true.minify: {removeAttributeQuotes:true
    },
    chunks: ['jquery'.'entry1'].// Chunk to be imported includes jquery and Entry
}),
new HtmlWebpackPlugin({
    filename:'login.html'.template:path.resolve(__dirname,'.. /public/template.html'),
    hash:true.minify: {removeAttributeQuotes:true
    },
    inject:false.// Inject false indicates that js files are not injected
    chunksSortMode:'manual'.// Manually configure the code block order
    chunks: ['entry2'.'jquery']})Copy the code

The above method is not very elegant. The HtmlPlugin should generate the HTML file dynamically each time you add it manually, like this:

let htmlPlugins = [
  {
    entry: "entry1".html: "index.html"
  },
  {
    entry: "entry2".html: "login.html"
  }
].map(
  item= >
    new HtmlWebpackPlugin({
      filename: item.html,
      template: path.resolve(__dirname, ".. /public/template.html"),
      hash: true.minify: {
        removeAttributeQuotes: true
      },
      chunks: ["jquery", item.entry]
    })
);
plugins: [...htmlPlugins]
Copy the code

Working with CSS files

Parsing CSS styles

We are introducing CSS styles in our JS files!

import './index.css';
Copy the code

When packaging is performed again, the CSS cannot be parsed

ERROR in ./src/index.css 1:4
Module parse failed: Unexpected token (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
Copy the code

Install the loader

npm install style-loader css-loader --save-dev
Copy the code
module: {
  rules: [{test: /\.css$/,
       use: ["style-loader"."css-loader"]]}}Copy the code

Extract the style file

By default, style extraction is only done at packaging time

module.exports = env= > {
  let isDev = env.development;
  const base = {/*source... * /}
  if (isDev) {
    return merge(base, dev);
  } else {
    returnmerge(base, prod); }};Copy the code

Install the pull-out plug-in

npm install mini-css-extract-plugin --save-dev
Copy the code

Configure the extraction plug-in

{
    test: /\.css$/,
    use: [
        !isDev && MiniCssExtractPlugin.loader,
        isDev && 'style-loader'."css-loader"
    ].filter(Boolean)}! isDev &&new MiniCssExtractPlugin({
    filename: "css/[name].css"
})
Copy the code

The final file configuration is posted below:

const path = require("path");
const dev = require("./webpack.dev");
const prod = require("./webpack.prod");
const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = env= > {
  let isDev = env.development;
  const base = {
    entry: "./src/index.js".output: {
      filename: "[name].js".path: path.resolve(__dirname, ".. /dist")},module: {
      rules: [{test: /\.css$/,
          use: [
            !isDev && MiniCssExtractPlugin.loader,
            isDev && 'style-loader'."css-loader"
          ].filter(Boolean)}}],plugins:[
        !isDev && new MiniCssExtractPlugin({
          filename: "css/[name].css"
        }),
        new HtmlWebpackPlugin({
          filename: "index.html".template: path.resolve(__dirname, ".. /public/template.html"),
          hash: true.minify: {
            removeAttributeQuotes: true
          }
        }),
      ].filter(Boolean)};if (isDev) {
    return merge(base, dev);
  } else {
    returnmerge(base, prod); }};Copy the code

CSS preprocessor

Different CSS preprocessors need to install different Loaders for parsing

  • sass: sass-loader node-sass
  • less: less-loader less
  • stylus: stylus-loader stylus

Using sass

{
    test:/\.scss$/,
    use:[
        !isDev && MiniCssExtractPlugin.loader,
        isDev && 'style-loader'."css-loader"."sass-loader"
    ].filter(Boolean)}Copy the code

A CSS file may be referenced using the @import syntax in the CSS file, and SCSS may also be imported into the referenced CSS file

{
    test: /\.css$/,
    use: [
    !isDev && MiniCssExtractPlugin.loader,
    isDev && 'style-loader',
    {
        loader:"css-loader".options: {importLoaders:1 // The imported files need to be processed by calling sass-loader}},"sass-loader"
    ].filter(Boolean)},Copy the code

Handling style prefixes

Add style prefixes using postCSs-loader

npm install postcss-loader postcss autoprefixer --save-dev
Copy the code

Add prefixes before working with CSS

 {
    test: /\.css$/,
    use: [
    !isDev && MiniCssExtractPlugin.loader,
    isDev && 'style-loader',
    {
        loader:"postcss-loader".options: {plugins: [require('autoprefixer')]}},"postcss-loader"."sass-loader"
    ].filter(Boolean)},Copy the code

Alternatively, you can create the postCSS configuration file postcss.config.js

module.exports = {
    plugins: [require('autoprefixer')]}Copy the code

You can configure the browser compatibility range. Browserslistrc

Cover 99.5%Copy the code

CSS compression

In production we need to compress the CSS file, configure the Minimizer option, and install the compression plugin

npm i optimize-css-assets-webpack-plugin terser-webpack-plugin --save-dev
Copy the code

Configure compression in the webpack.prod.js file

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
optimization:{
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})]
}
Copy the code

File fingerprint

  • Hash Hash value of the entire project
  • Chunkhash generates a hash value based on the entry
  • ContentHash Hash value generated based on the contents of each file

We can reasonably use hash stamps to cache files

! isDev &&new MiniCssExtractPlugin({
    filename: "css/[name].[contentHash].css"
})
Copy the code

Processing images

Processing referenced images

import logo from './webpack.png';
let img = document.createElement('img');
img.src = logo;
document.body.appendChild(img);
Copy the code

Using file-loader, the image is packed and the packed path is returned

{
    test:/\.jpe?g|png|gif/,
    use:{
        loader:'file-loader'.options: {name:`img/[name].[ext]`}}}Copy the code

Processing icon

Binary files are also packaged using file-loader

{
    test:/woff|ttf|eot|svg|otf/,
    use:{
        loader:'file-loader'}}Copy the code

Into base64

The url-loader is used to convert the images that meet the requirements into base64. If the url-loader does not meet the requirements, the url-loader automatically invokes file-loader to process the images

{
    test:/\.jpe?g|png|gif/,
    use:{
        loader:'url-loader'.options: {limit: 1.esModule: false.// name:`img/[name].[ext]`,
            name: function(file) {
              returnfile; }}}}Copy the code

Working with JS modules

willes6Code compiled intoes5code

The translation of the code is left to Babel

npm install @babel/core @babel/preset-env babel-loader --save-dev
Copy the code

@babel/core is the core module in Babel, and @babel/preset-env is the set of ES6 to transform ES5 plug-ins. Babel-loader is the bridge between WebPack and Loader.

const sum = (a, b) = > {
  return a + b;
};
Copy the code

Add Babel configuration file.babelrc

{
    "presets": [["@babel/preset-env"]]}Copy the code

Configure the loader

module: {
	rules: [{ test: /\.js$/, use: "babel-loader"}},Copy the code

Packaging now successfully converts ES6 syntax to ES5 syntax!

Parsing decorator

npm i @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators --save-dev
Copy the code
"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }],
  ["@babel/plugin-proposal-class-properties", {"loose":true}]]Copy the code

Legacy: True indicates that the decorator decorator is continued. When loose is false, object.defineProperty is used to define properties

  • Plugin will run ahead of Preset
  • Plugin will run sequentially starting from the first, Preset is reversed

polyfill

Using @babel/polyfill, modify the configuration as follows:

module.exports = {
  entry: ['@babel/polyfill'.'./src/index.js'].module: {
    rules: [{
      test: /\.jsx? $/,
      use: {
        loader: 'babel-loader'.options: {
          "presets": [["@babel/preset-env",
              {
                useBuiltIns: "entry"}]],"plugins"}},}]}}Copy the code

No matter what happens, you can import all compatibility packages into the system to support the lower version.

Disadvantages:

  • The volume was increased to 470KiB, or 87.2 KiB after compression, up from 345 bytes, an increase of several hundred times.

To optimize the

Fortunately, Babel7 will now support on-demand import. You can reduce the size of compatible packages by simply iterating through your code to find the modules you need to introduce. Thus reducing packaging volume.

Configuration:

 "presets": [["@babel/preset-env",
              {
                // debug:true, // Enable debug
                useBuiltIns: "usage".// Import on demand
                corejs: {
                  version: 3.proposals: true
                },
                 targets: {  // Support compatible versions
                   android: '4.2'.ios: '9'}}]Copy the code

Compiled and packaged: 114 KiB in volume and 19.8 KiB in compression. It’s a lot smaller. Isn’t it already perfect!! But there are drawbacks.

Disadvantages: This approach adds methods globally and modifies the prototype directly. This can cause global contamination and overwrite each other if others customize and extend the same method.

@babel/plugin-transform-runtime

This plug-in solves the problem of global contamination.

Change the configuration

 "plugins": [['@babel/plugin-transform-runtime', {corejs:3.helpers: true.regenerator: true}]]Copy the code

Code volume: 157 KiB, compressed volume: 26.7 KiB. By comparison, the volume is a little bit larger. So what’s the difference in packaged code? Let’s take a look.

No compiled code for transform-Runtime configured

Configure the compiled code after transform-Runtime

We found transform-Runtime changed all the code we had written. It’s been repackaged so there’s no global contamination.

To compare

volume Compressed volume conclusion
Use full import, @babel/polyfill 470KiB 87.2 KiB Best not to use
According to the need to introduce 114 KiB 19.8 KiB It is suitable for project development
transform-runtime 157 KiB  26.7 KiB This is appropriate when writing a library

See Resources to understand the Babel configuration

Check the CSS, js

Check js

  • eslint
  • eslint-loader
  • configuring
  • babel-eslint
  • Rules
  • ESlint syntax checks configuration instructions

The standard configuration

  • It is recommended to develop the esLint specification for your team
  • Improvements based on the ESLint: Recommend configuration
  • Turn on as many rules as possible to find code errors
  • Helps keep the team’s code style consistent without limiting the development experience

npm install eslint eslint-loader babel-eslint –D

{
    test: /\.(js|vue)$/,
    loader: 'eslint-loader',
    enforce: 'pre',
    include: [path.resolve(root, 'src')],
    options: {
        formatter: require('eslint-friendly-formatter'),
      	fix: true}}Copy the code

Note: eslint-friendly-formatter: indicates a friendly prompt; Enforce: “pre”; This attribute must be added or there will be a problem. The main function of this attribute is to make the loader execute before all loaders execute.

.eslintrc.js

module.exports = {
    root: true,
    parserOptions: {
        parser: 'babel-eslint',
        sourceType: 'module'
    },
    env: {
        browser: true,
        node: true,
        es6: true
    },
    plugins: [
        "html"
    ],
    settings: {
        "html/html-extensions": [".html"]."html/indent": "0".// code should start at the beginning of the line (no initial indentation).
        "html/indent": "+ 4".// indentation is the <script> indentation plus two spaces.
        "html/indent": "tab".// indentation is one tab at the beginning of the line.
        "html/report-bad-indent": "error"."html/javascript-mime-types": ["text/javascript"."text/jsx"]
    },
    extends: ['plugin:vue/recommended', 'eslint:recommended'],
    // add your custom rules here
    // http://eslint.cn/docs/rules/
    // https://cn.eslint.org/docs/user-guide/configuring
    rules: {
        //vue
        "vue/no-use-v-if-with-v-for": 2.// Disallow v-if on the same element as v-for

        //un vue
        'indent': [2.4, {
            'SwitchCase': 2 // The case clause will be indented 4 Spaces relative to the switch statement}].// Enforce consistent indentation
        'quotes': [2, 'single', {
            'avoidEscape': true,
            'allowTemplateLiterals': true}].// Enforces consistent backticks, double quotes, or single quotes
        'no-mixed-spaces-and-tabs': 2.// Disallow the combination of space and TAB indentation
        'jsx-quotes': [2, 'prefer-single'], // Enforce consistent use of double or single quotes in JSX attributes
        'comma-dangle': [2, 'never'], // Require or disallow trailing commas
        'no-dupe-keys': 2.Disallow duplicate keys in object literals
        'no-eval': 2./ / disable the eval ()
        'no-implied-eval': 2.// Disallow methods like eval()
        'no-with': 2.// Disable the with statement
        'no-redeclare': 2.// Do not declare the same variable more than once
        'no-undef': 2.// Disable undeclared variables unless they are mentioned in the /*global */ comment
        'no-undef-init': 2.// Disallow initializing variables as undefined
        'prefer-const': 2.// Require const to declare variables that are no longer modified after being declared
        'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0./ / disable the debugger
        'no-console': process.env.NODE_ENV === 'production' ? 2 : 0./ / disable the console

        //undetermined
        "vue/max-attributes-per-line": [2, {
            "singleline": 10."multiline": {
                "max": 1."allowFirstLine": false}}].// Enforces a maximum number of attributes per row
        "vue/singleline-html-element-content-newline": 0.// Line breaks are required before and after the content of the single-line element
        "vue/multiline-html-element-content-newline": 0.// Newlines are required before and after the content of multi-line elements
        "vue/name-property-casing": [2."PascalCase"].// Enforces a specific case (underscore) for the name attribute in the Vue component
        'accessor-pairs': 2.// Forces getters and setters to pair in objects
        'arrow-spacing': [1, {
            'before': true,
            'after': true}].// Forces the arrow function to use consistent Spaces before and after the arrow
        'block-spacing': [2, 'always'], // Disallows or enforces Spaces before and after opening and closing parentheses in code blocks
        'brace-style': [2, '1tbs', {
            'allowSingleLine': true // (default false) allows the opening and closing brackets of a block to be on the same line}].// Enforce a consistent brace style in code blocks
        'camelcase': [0, {
            'properties': 'always' //(default) Force the attribute name to be hump style}].// Enforce camel spelling naming conventions
        'comma-spacing': [2, {
            'before': false,
            'after': true}].// Enforces consistent Spaces around commas
        'comma-style': [2, 'last'], // Enforce a consistent comma style
        'constructor-super': 2.// Requires a call to super() in the constructor
        'curly': [2, 'multi-line'], // Force all control statements to use the same parenthesis style
        'dot-location': [2, 'property'], // Enforces line breaks before and after the dot
        'eol-last': 2.// Require or disallow blank lines at the end of the file
        'generator-star-spacing': [2, {
            'before': true,
            'after': true}].// Force a consistent space around the * in generator functions
        'handle-callback-err': [0, '^(err|error)$'], // Error tolerance is required in the callback function
        'key-spacing': [2, {
            'beforeColon': false,
            'afterColon': true}].Enforces consistent spacing between keys and values in attributes of object literals
        'keyword-spacing': [2, {
            'before': true,
            'after': true}].// Enforces consistent Spaces around keywords
        'new-cap': [2, {
            'newIsCap': true.//(default true) requires a function of initial size when calling the new operator
            'capIsNew': false // Allows calls to uppercase functions without the new operator}].// Require the constructor to begin with a capital letter
        'new-parens': 2.// require parentheses when calling the no-argument constructor
        'no-array-constructor': 2.// Disable the Array constructor
        'no-caller': 2.// Disable arguments.caller or arguments.callee
        'no-class-assign': 2.// Disallow modifying class declared variables
        'no-cond-assign': 0.// Disallow assignment operators in conditional expressions
        'no-const-assign': 2.// Disallow modifying variables declared by const
        'no-control-regex': 2.// Disallow control characters in regular expressions
        'no-delete-var': 2.// Disable variable deletion
        'no-dupe-args': 2.// Disallow duplicate arguments in function definitions
        'no-dupe-class-members': 2.// Disallow duplicate names in class members
        'no-duplicate-case': 2.// Disallow duplicate case tags
        'no-empty-character-class': 2.// Disallow null character sets in regular expressions
        'no-empty-pattern': 2.// Disallow empty destruct mode
        'no-ex-assign': 2.// Disallows reassignment of the parameters of the catch clause
        'no-extend-native': 2.// Forbid extending native types
        'no-extra-bind': 2.// Disallow unnecessary.bind() calls
        'no-extra-boolean-cast': 2.// Disable unnecessary Boolean conversions
        'no-extra-parens': [2, 'functions'], // Disallow unnecessary parentheses
        'no-fallthrough': 2.// Disallow case statements from falling through
        'no-floating-decimal': 2.// Disallow leading and trailing decimal points in numeric literals
        'no-func-assign': 2.// Disallow reassignment of function declarations
        'no-inner-declarations': [2, 'functions'], // Disallow variable or function declarations in nested blocks
        'no-invalid-regexp': 2.// Disallow invalid regular expression strings in the RegExp constructor
        'no-irregular-whitespace': 2.// Disallow irregular whitespace outside strings and comments
        'no-iterator': 2.// Disable the __iterator__ attribute
        'no-label-var': 2.// Labels are not allowed to have the same name as variables
        'no-labels': [2, {
            'allowLoop': false,
            'allowSwitch': false}].// Disable label statements
        'no-lone-blocks': 2.// Disable unnecessary nesting blocks
        'no-multi-spaces': 2.// Disallow multiple Spaces
        'no-multi-str': 2.// Disallow multi-line strings
        'no-multiple-empty-lines': [2, {
            'max': 1}].// Disallow multiple blank lines
        'no-global-assign': 2.// Disallow assignment to native or read-only global objects
        'no-unsafe-negation': 2.// Disallow the negation operator on the left-hand operand of relational operators
        'no-new-object': 2.// Disable the Object constructor
        'no-new-require': 2.// Disallow the new operator when calling require
        'no-new-symbol': 2.// Disallow the Symbolnew operator from being used with new
        'no-new-wrappers': 2.// Disallow the new operator for String, Number, and Boolean
        'no-obj-calls': 2.// Disallow calling global objects as functions
        'no-octal': 2.// Disable octal literals
        'no-octal-escape': 2.// Disallow octal escape sequences in strings
        'no-path-concat': 2.// Disallow string concatenation of __dirname and __filename
        'no-proto': 2.// Disable the __proto__ attribute
        'no-regex-spaces': 2.Disallow multiple Spaces in regular expression literals
        'no-return-assign': [2, 'except-parens'], // Disallow assignment statements in return statements
        'no-self-assign': 2.// Disallow self-assignment
        'no-self-compare': 2.// Disallow self comparison
        'no-sequences': 2.// Disable the comma operator
        'no-shadow-restricted-names': 2.// Disallow defining identifiers as restricted names
        'func-call-spacing': 2.// Requires or disallows Spaces between function identifiers and their calls
        'no-sparse-arrays': 2.// Disable sparse arrays
        'no-this-before-super': 2.// Disallow this or super before calling super() in constructors
        'no-throw-literal': 2.// Disallow throwing exception literals
        'no-trailing-spaces': 2.// Disable end-of-line whitespace
        'no-unexpected-multiline': 2.// Disallow confusing multi-line expressions
        'no-unmodified-loop-condition': 2.// Disable immutable loop conditions
        'no-unneeded-ternary': [2, {
            'defaultAssignment': false}].// Disallow ternary operators when simpler alternative expressions are available
        'no-unreachable': 2.// Disallows unreachable code after return, throw, continue, and break statements
        'no-unsafe-finally': 2.// Disallow control flow statements in finally blocks
        'no-unused-vars': [2, {
            'vars': 'all',
            'args': 'none'
        }], // Disallow unused variables
        'no-useless-call': 2.// Disallow unnecessary.call() and.apply()
        'no-useless-computed-key': 2.// Disallow unnecessary computed attributes in objects
        'no-useless-constructor': 2.// Disable unnecessary constructors
        'no-useless-escape': 0.// Disable unnecessary escape characters
        'no-whitespace-before-property': 2.// Disallow whitespace before attributes
        'one-var': [2, {
            'initialized': 'never'
        }], // Forces variables in a function to be declared either together or separately
        'operator-linebreak': [2, 'after', { 'overrides': { '? ': 'before', ':': 'before' } }],// Forces operators to use consistent line breaks
        'padded-blocks': [2, 'never'], // Requires or disallows in-block padding
        'semi': [2, 'always'], Require or disallow semicolons instead of ASI
        'semi-spacing': [2, {
            'before': false,
            'after': true}].// Enforces consistent Spaces before and after semicolons
        'space-before-blocks': [2, 'always'], // Enforces consistent whitespace before blocks
        'space-before-function-paren': [2, 'never'], // Enforces a consistent space before the opening parenthesis of function
        'space-in-parens': [2, 'never'], // Enforces consistent Spaces inside parentheses
        'space-infix-ops': 2.// Requires Spaces around the operator
        'space-unary-ops': [2, {
            'words': true,
            'nonwords': false}].// Enforces consistent Spaces around unary operators
        'spaced-comment': [2, 'always', {
            'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
        }], // Enforces consistent whitespace in comments
        'template-curly-spacing': [2, 'never'], // Requires or disallows the use of whitespace around embedded expressions in template strings
        'use-isnan': 2.// Require isNaN() to check NaN
        'valid-typeof': 2.// Forces typeof expressions to be compared with valid strings
        'wrap-iife': [2, 'any'], // Require IIFE to be enclosed in parentheses
        'yield-star-spacing': [2, 'both'], // Enforces whitespace around * in yield* expressions
        'yoda': [2, 'never'], // Require or disallow the "Yoda" condition
        'object-curly-spacing': [2, 'always', {
            objectsInObjects: false}].// Enforces consistent Spaces in braces
        'array-bracket-spacing': [2, 'never'] // Enforces consistent Spaces in array square brackets}}Copy the code

CSS validation

stylelint

The installation

npm install –save-dev stylelint stylelint-config-standard

check

npx stylelint “**/*.css”

Used in combination with PostCSS

const fs = require("fs");
const less = require("postcss-less");
const postcss = require("postcss");

// Code to be processed
const code = fs.readFileSync("input.less"."utf8");

postcss([
  require("stylelint") ({/* your options */
  }),
  require("postcss-reporter")({ clearReportedMessages: true })
])
  .process(code, {
    from: "input.less",
    syntax: less
  })
  .then(() => {})
  .catch((err) => console.error(err.stack));
Copy the code

References:

Stylelint postcss plug-in

. Stylelintrc file

{ 
  "extends": "stylelint-config-standard"."plugins": ["stylelint-order"]."rules": {
    "order/order": [
      "declarations"."custom-properties"."dollar-variables"."rules"."at-rules"]."order/properties-order": [
      "position"."z-index"."top"."bottom"."left"."right"."float"."clear"."columns"."columns-width"."columns-count"."column-rule"."column-rule-width"."column-rule-style"."column-rule-color"."column-fill"."column-span"."column-gap"."display"."grid"."grid-template-rows"."grid-template-columns"."grid-template-areas"."grid-auto-rows"."grid-auto-columns"."grid-auto-flow"."grid-column-gap"."grid-row-gap"."grid-template"."grid-template-rows"."grid-template-columns"."grid-template-areas"."grid-gap"."grid-row-gap"."grid-column-gap"."grid-area"."grid-row-start"."grid-row-end"."grid-column-start"."grid-column-end"."grid-column"."grid-column-start"."grid-column-end"."grid-row"."grid-row-start"."grid-row-end"."flex"."flex-grow"."flex-shrink"."flex-basis"."flex-flow"."flex-direction"."flex-wrap"."justify-content"."align-content"."align-items"."align-self"."order"."table-layout"."empty-cells"."caption-side"."border-collapse"."border-spacing"."list-style"."list-style-type"."list-style-position"."list-style-image"."ruby-align"."ruby-merge"."ruby-position"."box-sizing"."width"."min-width"."max-width"."height"."min-height"."max-height"."padding"."padding-top"."padding-right"."padding-bottom"."padding-left"."margin"."margin-top"."margin-right"."margin-bottom"."margin-left"."border"."border-width"."border-top-width"."border-right-width"."border-bottom-width"."border-left-width"."border-style"."border-top-style"."border-right-style"."border-bottom-style"."border-left-style"."border-color"."border-top-color"."border-right-color"."border-bottom-color"."border-left-color"."border-image"."border-image-source"."border-image-slice"."border-image-width"."border-image-outset"."border-image-repeat"."border-top"."border-top-width"."border-top-style"."border-top-color"."border-top"."border-right-width"."border-right-style"."border-right-color"."border-bottom"."border-bottom-width"."border-bottom-style"."border-bottom-color"."border-left"."border-left-width"."border-left-style"."border-left-color"."border-radius"."border-top-right-radius"."border-bottom-right-radius"."border-bottom-left-radius"."border-top-left-radius"."outline"."outline-width"."outline-color"."outline-style"."outline-offset"."overflow"."overflow-x"."overflow-y"."resize"."visibility"."font"."font-style"."font-variant"."font-weight"."font-stretch"."font-size"."font-family"."font-synthesis"."font-size-adjust"."font-kerning"."line-height"."text-align"."text-align-last"."vertical-align"."text-overflow"."text-justify"."text-transform"."text-indent"."text-emphasis"."text-emphasis-style"."text-emphasis-color"."text-emphasis-position"."text-decoration"."text-decoration-color"."text-decoration-style"."text-decoration-line"."text-underline-position"."text-shadow"."white-space"."overflow-wrap"."word-wrap"."word-break"."line-break"."hyphens"."letter-spacing"."word-spacing"."quotes"."tab-size"."orphans"."writing-mode"."text-combine-upright"."unicode-bidi"."text-orientation"."direction"."text-rendering"."font-feature-settings"."font-language-override"."image-rendering"."image-orientation"."image-resolution"."shape-image-threshold"."shape-outside"."shape-margin"."color"."background"."background-image"."background-position"."background-size"."background-repeat"."background-origin"."background-clip"."background-attachment"."background-color"."background-blend-mode"."isolation"."clip-path"."mask"."mask-image"."mask-mode"."mask-position"."mask-size"."mask-repeat"."mask-origin"."mask-clip"."mask-composite"."mask-type"."filter"."box-shadow"."opacity"."transform-style"."transform"."transform-box"."transform-origin"."perspective"."perspective-origin"."backface-visibility"."transition"."transition-property"."transition-duration"."transition-timing-function"."transition-delay"."animation"."animation-name"."animation-duration"."animation-timing-function"."animation-delay"."animation-iteration-count"."animation-direction"."animation-fill-mode"."animation-play-state"."scroll-behavior"."scroll-snap-type"."scroll-snap-destination"."scroll-snap-coordinate"."cursor"."touch-action"."caret-color"."ime-mode"."object-fit"."object-position"."content"."counter-reset"."counter-increment"."will-change"."pointer-events"."all"."page-break-before"."page-break-after"."page-break-inside"."widows"]."no-empty-source": null."property-no-vendor-prefix": [true, {"ignoreProperties": ["background-clip"."box-orient"]}],
    "number-leading-zero": "never"."number-no-trailing-zeros": true."length-zero-no-unit": true."property-no-unknown": [true, {"ignoreProperties": ["box-orient"]}],
    "value-list-comma-space-after": "always"."declaration-colon-space-after": "always"."value-list-max-empty-lines": 0."shorthand-property-no-redundant-values": true."declaration-block-no-duplicate-properties": true."declaration-block-no-redundant-longhand-properties": true."declaration-block-semicolon-newline-after": "always"."block-closing-brace-newline-after": "always"."media-feature-colon-space-after": "always"."media-feature-range-operator-space-after": "always"."at-rule-name-space-after": "always"."indentation": 4."no-eol-whitespace": true."string-no-newline": null}}Copy the code

Vue compilation is supported

const { VueLoaderPlugin } = require('vue-loader');

{
  test: /\.vue$/,
  use: [
    'cache-loader',
    {
      loader: 'vue-loader',
      options: {
        // other vue-loader options go here
      }
    }
  ]
}

plugins:[new VueLoaderPlugin()]

Copy the code

Configure the TS development ring

Use ts – loader

To use the TS, you need to install the TS-related configuration

npm install typescript ts-loader --save-dev
Copy the code

Generate the TS configuration file

npx tsc --init
Copy the code

Configuration ts – loader

{
    test:/\.tsx? /,
    use: ['ts-loader'].exclude: /node_modules/
}
Copy the code

Change the import file to ts file

let a:string = 'hello';
console.log(a);
Copy the code

NPM run dev: Ts file parsed properly.

Use the preset – typescript

You don’t need typescript

npm install @babel/preset-typescript
Copy the code
{
    "presets": [["@babel/preset-env", {"useBuiltIns":"usage"."corejs":2}]."@babel/preset-react"["@babel/preset-typescript", {"allExtensions": true}]],"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }],
        ["@babel/plugin-proposal-class-properties", {"loose":true}]."@babel/plugin-transform-runtime"]}Copy the code

Configure the TS and React environment

Install the React module

npm i @babel/preset-react --save-dev # Parse JSX syntax
npm i react @types/react @types/react-dom react react-dom typescript
Copy the code
import React from 'react';
import ReactDOM from 'react-dom';
const state = {number:0};
type State = Readonly<typeof state>;
class Counter extends React.Component<object.State>{
    state:State = state
    handleClick =() = >{
        this.setState({number:this.state.number+1})}render(){
        const {number} = this.state;
        return (
            <div>
                <button onClick={this.handleClick}>Click on the</button>
                {number}
            </div>
        )
    }
}
ReactDOM.render(<Counter></Counter>.document.getElementById('root'));
Copy the code

Configure the TS + VUE environment

Install the modules required by vUE

npm install vue-loader  vue-template-compiler --save-dev
npm install vue vue-property-decorator
Copy the code

Configuration ts – loader

{
    test: /\.tsx? /,
    use: {
        loader:'ts-loader'.options: {
            appendTsSuffixTo: [/\.vue$/],}},exclude: /node_modules/
}
Copy the code

Use vue-loader plug-in

const VueLoaderPlugin = require('vue-loader/lib/plugin');
new VueLoaderPlugin();
Copy the code

Configure parsing. Vue files

{
    test:/\.vue$/,
    use:'vue-loader'
}
Copy the code

Added vue-shims.d.ts to recognize. Vue files

declare module '*.vue' {
    import Vue from 'vue';
    export default Vue;
}
Copy the code

Index. The TSX composite file

import Vue from 'vue';
import App from './App.vue';
let vm = new Vue({
    render:h= >h(App)
}).$mount('#root')
Copy the code

App. Vue file

<template>
    <div>
        <div v-for="(todo,index) in todos" :key="index">{{todo}}</div>
    </div>
</template>
<script lang="ts">
import {Component,Vue} from 'vue-property-decorator';
@Component
export default class Todo extends Vue{
    public todos = ['banana'.'apple'.'orange']}</script>
Copy the code

Common plugin

const CopyWebpackPlugin = require('copy-webpack-plugin'); / / copy
const HappyPack = require('happypack'); // Multi-process running
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');/ / CSS compression
const TerserPlugin = require('terser-webpack-plugin');
const happyThreadPool = HappyPack.ThreadPool({
    size: os.cpus().length
});
rules:[
  {
    test: /\.(j|t)sx?$/,
    use: 'happypack/loader?id=happy-babel-js' // Add new HappyPack build loader
  }
],
plugins: [
    new CopyWebpackPlugin([
      {
        from: './src/common',
        to: './common'
      }
    ]),
    new HappyPack({
      id: 'happy-babel-js',
      loaders: [
        'cache-loader',
        {
          loader: 'babel-loader'
        }
      ],
      threadPool: happyThreadPool
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      aaa: JSON.stringify({
        version: 'version',
      })
    }),
  	new OptimizeCssAssetsPlugin(),
    new webpack.HashedModuleIdsPlugin({
      hashDigest: 'hex'
    }),
    new webpack.NamedChunksPlugin((chunk) => {
      if (chunk.name) {
        return chunk.name;
      }

      const hash = require('hash-sum');
      const joinedHash = hash(
        Array.from(chunk.modulesIterable, (m) => m.id).join('_')
      );
      return `chunk-` + joinedHash;
    })
],
optimization: {
    minimize: true,
    minimizer: [new TerserPlugin({
      extractComments: false,
      terserOptions: {
        output: {
          comments: false
        },
        cache: true.// Enable caching
        parallel: true.// Enable multi-threaded compression
        compress: { / / configuration
          // It is necessary to open it
          warnings: true.// Turn off warnings: Display warnings when deleting unreachable code or unused declarations, etc
          drop_console: true,
          drop_debugger: true}}}})]Copy the code

source map

  • Sourcemap is a technology designed to help us debug the original development code when it is inconsistent with the actual running code
  • Webpack can be configured to give us automaticallysource mapsFile,mapA file is a method that corresponds to a compiled file and a source file
  • whyeval
  • source-map
  • Javascript_source_map algorithm
type meaning
source-map The sourcemap quality of the best raw code has complete results, but is slow
eval-source-map The original code is the same, but of the highest quality and lowest performance
cheap-module-eval-source-map The original code (inline only) does the same, but with higher quality and lower performance
cheap-eval-source-map The conversion code (inline) is executed by EVAL for each module, and sourcemap acts as a dataURL for Eval
eval Generated code is eval for each module, and @sourceURL exists. Build mode with EVAL can cache SourceMap
cheap-source-map The sourcemap generated by the conversion code (inline) has no column mapping, and the Sourcemap generated from loaders is not used
cheap-module-source-map The original code (inline only) is the same as above except for each line characteristic mapped from the Loader

What looks like a lot of configuration items are just any combination of the five keywords eval, source-map, cheap, module, and inline

The keyword meaning
eval Wrap module code in eval
source-map Generate the.map file
cheap Contains no column information (more on column information below) and no Sourcemap for the Loader
module Include loader’s sourcemap (such as JSX to JS, Babel’s sourcemap), otherwise the source file cannot be defined
inline Embed.map as a DataURI without generating a separate.map file
  • The eval eval perform
  • The eval – source – generate sourcemap map
  • Cheap-module-eval-source-map does not contain columns
  • Cheap -eval-source-map cannot see the actual source code

Devtool :”cheap-module-eval-source-map”,// development environment configuration

reference

Reference documentation

  • webpack-start
  • resolve

List of Common Loaders

  • Webpack can use loader to preprocess files. This allows you to package any static resources other than JavaScript. You can easily write your own loader using Node.js.
  • awesome-loaders

file

  • Raw -loader Load file raw content (UTF-8)
  • Val-loader executes the code as a module and exports to JS code
  • Url-loader works like a file loader, but returns a data URL if the file is smaller than the limit
  • File-loader sends the file to the output folder and returns the (relative) URL

JSON

  • Json-loader loads JSON files (default included)
  • Json5-loader loads and translates JSON 5 files
  • Cson -loader loads and translates Cson files

Transpiling

  • Script-loader executes a JavaScript file (such as in a script tag) once in a global context, without parsing
  • Babel-loader loads the ES2015+ code and then translates it to ES5 using Babel
  • Buble-loader uses buble to load ES2015+ code and translate the code to ES5
  • Traceur – Loader loads the ES2015+ code and then translates it into ES5 using traceur
  • Ts-loader or awesome-typescript-loader loads typescript 2.0+ like JavaScript
  • Coffee-loader loads CoffeeScript like JavaScript

Template (Templating)

  • Html-loader exports HTML as a string and references static resources
  • Pug-loader loads the PUg template and returns a function
  • Jade-loader loads the Jade template and returns a function
  • Markdown-loader translates markdown to HTML
  • React-markdown-loader compiles markdown into the React component using markdown-parse parser
  • Posthtml -loader uses PosthTML to load and convert HTML files
  • Handlebars -loader transfers handlebars to HTML
  • Markup -inline-loader converts an inline SVG/MathML file to HTML. Useful when applying icon fonts, or CSS animations to SVG

style

  • Style-loader adds the module’s export to the DOM as a style
  • Css-loader parses the CSS file, loads it using import, and returns the CSS code
  • Less-loader loads and translates less files
  • Sass -loader loads and translates SASS/SCSS files
  • Postcss-loader Loads and translates CSS/SSS files using postCSS
  • Stylus – Loader loads and translates stylus files

Linting && Testing

  • Mocha – Loader using Mocha tests (browser /NodeJS)
  • Eslint-loader PreLoader, which uses esLint to clean code
  • Jshint-loader PreLoader: uses jshint to clear codes
  • Jscs-loader PreLoader: uses JSCS to check code styles
  • Coverjs-loader PreLoader, which uses CoverJS to determine test coverage

Framework (Frameworks)

  • Vue-loader loads and translates VUE components
  • Polymer-loader is processed using a selective preprocessor and requires () Web components similar to first-class modules
  • Angular2-template-loader loads and translates Angular components