webpack core foundation

webpack is no longer our pain point - core foundation

Webpack has always been a pain point for front-end engineers. Because of its complexity, dispersion, loader, plugin and other third parties, our learning cost has risen sharply, and we have always been ambiguous about his configuration. Today, I will show you how to configure it and get rid of the trouble. Our pain point for a long time. This article is mainly a detailed explanation of the basic configuration of webpack. The module chunk, compilation phase process, output phase process, loader writing and handwritten plugin of webpack will be launched in subsequent articles. In order to avoid missing, you can follow me or bookmark my personal blog www.ngaiwe .com

1. What is webpack?

WebPack can be seen as a module packer: what it does is, analyze your project structure, find JavaScript modules and other extension languages ​​(Scss, TypeScript, etc.) that browsers cannot run directly, and package them into appropriate format for browser use. And follow your various needs in the project, realize automatic processing, and liberate our productivity

  • Code conversion: TypeScript is compiled into JavaScript, SCSS is compiled into CSS.
  • File optimization: compress JavaScript, CSS, HTML code, compress and merge images, etc.
  • Code splitting: Extract common code of multiple pages, extract code that does not need to be executed on the first screen, and let it load asynchronously.
  • Module merging: In a modular project, there will be many modules and files, and a build function is required to classify and merge the modules into one file.
  • Auto refresh: monitor local source code changes, rebuild and refresh the browser automatically.
  • Code verification: Before the code is submitted to the warehouse, it is necessary to verify whether the code conforms to the specification and whether the unit test passes.
  • Automatic release: After the code is updated, the online release code is automatically constructed and transmitted to the release system.

2. Project initialization

mkdir webpack-start
cd webpack-start
npm init

3. Core concepts of webpack

  • Entry: Entry, the first step of webpack's construction will start from Entry, which can be abstractly understood as input
  • Module: module, everything is a module in webpacl, a module corresponds to a file, webpack will recursively find all dependent modules from the configured Entry
  • Chunk: code block, a chunk is composed of multiple modules, used to combine and split code
  • Loader: module converter, which is used to convert the original content of the module into the new content required according to the requirements
  • Plugin: Extension plugin that injects extension logic at specific times in the webpack build process to change the build result and what it wants to do
  • Output: Input the result, go through a series of processing in webpack and get the final desired code and then output the result

After Webpack starts, it Entrywill Modulerecursively resolve all Modules that Entry depends on from the configuration in . Each time a Module is found, the Loadercorresponding conversion rules will be found according to the configuration, and after the Module is converted, the Module that the current Module depends on will be parsed. These modules are grouped in units of Entry, an Entry and all its dependent Modules are grouped into a group that is one Chunk. Finally, Webpack will convert all chunks into file output. During the whole process, Webpack will execute the logic defined in the Plugin at the right time.

1.Entry

The context is used to solve that the configuration file and the entry file are no longer in the same layer structure. For example, our configuration file is in config and the entry file is in the root directory, then the configuration is as follows

module.exports = {
  context: path.join(__dirname, '..'), // 找到根目录
  entry: './main.js' //根目录下的入口文件
}

The simplest single page (SPA) Entry entry, import main.js, and start parsing according to the modules referenced and dependent in main.js

module.exports = {
  entry: './main.js'
}

Multi-page (MPA) Entry entry, import multiple files, of course, generally read the entry file in the specified folder, and then import

entry: {
  home: "./home.js",
  about: "./about.js",
  contact: "./contact.js"
}

If it is a single page (a string or an array of strings is passed in), the chunk will be named main, if it is a multi-page (an object is passed in), each key (key) will be the name of the chunk, description the entry point of the chunk

2.Output

Object instructs webpack how to export, and where to export your bundles, assets, and anything else you bundle or load with webpack

  • path: the output directory corresponds to an absolute path

    path: path.resolve(__dirname, 'dist')
    
  • pathinfo: boolean The default function of false is to tell webpack to introduce relevant comments about the module information contained in the bundle, which should not be used in the production environment (production) and is extremely useful for the development environment (development).

  • publicPath: The main function is to process the static file path in the packaged file

  • filename: defines the name of each output bundle, which will be written to the directory specified by the output.path option. For single-entry Entry, filename is a static name

    filename: "bundle.js"
    

    But in webpack we will use code splitting, various plugin plugins or multi-entry Entry to create multiple bundles, so we should give each bundle a unique name

    filename: "[name].bundle.js"
    

    use internal chunk id

    filename: "[id].bundle.js"
    

    Unique hash generation

    filename: "[name].[hash].bundle.js"
    

    Use a hash based on the content of each chunk

    filename: "[chunkhash].bundle.js"
    
3.Module module

Processing different modules applied in the project, the main configuration is in Rules, matching the requested rule array, these rules can apply loader to the module, or modify the parser parser

  • Module.noParse: Prevents webpack from parsing files with successful rules matching and ignoring large libraries to optimize performance. The ignored files should not contain calls to import, require and define

    module.exports = {
      module: {
        rules: [],
        noParse: function(content) {
          return /jquery|lodash/.test(content) // 忽略jquery文件解析,直接编译打包
        }
      }
    }
    
  • Rules: When creating a module, an array of rules that match the request

    • Rule conditions: resource (absolute path of the requested file), issuer (absolute path of the module file of the requested resource, the location when importing), for example, a file A imports file B, resource is /B, issuer is /A is the import file Instead of the real location, in the rule, test/include/exclude/resource matches resource, and issuer matches only issuer

    • Usage and difference of Test/include/exclude/resource/issuer

      module.exports = {
          modules: {
              rules: [
                {
                  test: /\.js?$/,
                  include: [
                    path.resolve(__dirname, "app")
                  ],
                  exclude: [
                    path.resolve(__dirname, "app/demo")
                  ],
                  resource:{
                    test: /\.js?$/,
                    include: path.resolve(__dirname, "app"),
                    exclude: path.resolve(__dirname, "app/demo")
                  },
                  issuer: {
                    test: /\.js?$/,
                    include: path.resolve(__dirname, "app"),
                    exclude: path.resolve(__dirname, "app/demo")
                  }
                }
              ]
        }
      }
      

      test: Generally, a regular expression or an array of regular expressions is provided. If the absolute path conforms to this regular expression, it means that this condition is met.

      include: is a string or an array of strings, the files in the specified directory need to follow this rule

      exclude: is also a string or an array of strings, the files in the specified directory do not need to follow this rule

      resource: It is an object wrapper for text/include/exclude, which is no different from writing them separately

      issuer: has the same function as resource, but the difference is that it applies the rule to which file and all dependent files imported by this file

    • resourceQuery: the same as the resource usage, but for the path parameters after the matching result '?', you can call the text in the resource, etc.

    • oneOf: Indicates that only the first matching rule is applied to the resource, generally combined with resourceQuery

      {
        test: /\.(png|jpe?g|gif|svg)$/,
        oneOf: [
          {
            resourceQuery: /inline/, 
            loader: 'url-loader'
          },
          {
            loader: 'file-loader'
          }
        ]
      }
      
      • path/to/foo.png?inline: will match url-loader
      • path/to/foo.png?other:会匹配file-loader
      • path/to/foo.png: will match file-loader
    • useEntry: object contains each loader and corresponds to the loader's configuration file

      {
        loader: "css-loader",
        options: {
          modules: true
        }
      }
      

      options will be passed into the loader, which can be understood as the options of the loader

    • use: is a collection of useEntry, and specifies the use of a loader for each entry

      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 1
          }
        },
        {
          loader: 'less-loader',
          options: {
            noIeCompat: true
          }
        }
      ]
      
4.Resolve analysis

Mainly used for how modules are parsed, providing default values ​​for webpack

  • alias: object is mainly used to make import and require calls more convenient, and to set the initial path

    module.exports = {
     alias: {
      Utilities: path.resolve(__dirname, 'src/utilities/'),
      Templates: path.resolve(__dirname, 'src/templates/')
     }   
    }
    // 最开始的import
    import Utility from '../../utilities/utility';
    // 配置完以后
    import Utility from 'Utilities/utility';
    
  • enforceExtension: Boolean The default is false, which means that the reference does not need an extension. When it is true, the reference in import and require must add an extension

  • extensions: Array auto-parsing does not require extensions

    extensions: [".js", ".json"]  // .js、.json引入不需要扩展名
    
  • modules: The directory that Array webpack needs to search when parsing modules, generally used to first search and custom modules in non-node_modules files

    modules: [path.resolve(__dirname, "src"), "node_modules"] //优先搜索src目录
    
5.Loader

By using different Loaders, Webpack can convert different files into JS files, such as CSS, ES6/7, JSX, etc., which are generally used in the use of modules

module: {
  rules:[
      {
        test:/\.css$/,
        use:['style-loader','css-loader'],
        include:path.join(__dirname,'./src'),
        exclude:/node_modules/
      }
  ]      
}

For specific related loaders, you need to check the official document API of the loader you want to introduce. The handwritten Loader will be introduced in the next article.

6. Plugin

Array extends webpack and injects extension logic at a specific time in the webpack build process to change the build result and what you want to do. For specific usage, check the official documentation of the plugin you introduced. The handwritten plugin will be launched in subsequent articles.

7.webpack-dev-server

The server under development, webpack-dev-server can quickly build a local service, see webpack-dev-server for specific usage

8.Devtool

This option controls whether to generate and how to generate it. Officially recommend SourceMapDevToolPlugin and source-map-loader . It is recommended to see the official documentation . Devtool is mainly used to control the quality of packaging, the ease of debugging in the dev environment, and the speed of compilation.

9.Watch

webpack can monitor file changes and recompile when they are modified

4. Configure webpack

webpack install command

npm install webpack webpack-cli -D

Webpack.config.js

The specific plugin used

  • clean-webpack-plugin: used to clear the output directory before packaging Official API
  • html-webpack-plugin: The official
  • copy-webpack-plugin: used to copy static resources, including unreferenced resources Official API
  • uglifyjs-webpack-plugin: used to compress JS, the output JS file can be smaller in size, faster to load, less traffic, and the encryption function of obfuscated code Official API
  • extract-text-webpack-plugin: Because the download of CSS and JS can be parallelized, when an HTML file is very large, we can extract the CSS separately and load it. Official API
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
// npm i extract-text-webpack-plugin@next // @next可以安装下一个非正式版本
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
let cssExtract = new ExtractTextWebpackPlugin({
    filename: 'css/css.css',
    allChunks: true
});
let lessExtract = new ExtractTextWebpackPlugin('css/less.css');
let sassExtract = new ExtractTextWebpackPlugin('css/sass.css');
/**
 * 有些时候我们希望把页面中的CSS文件单独拉出来保存加载
 * extract-text-webpack-plugin
 */
//let pages = ['index', 'base'];
// pages = pages.map(page => new HtmlWebpackPlugin({
//     template: './src/index.html',//指定产的HTML模板
//     filename: `${page}.html`,//产出的HTML文件名
//     title: `${page}`,
//     chunks: ['common', `${page}`],//在产出的HTML文件里引入哪些代码块
//     hash: true,// 会在引入的js里加入查询字符串避免缓存,
//     minify: {
//         removeAttributeQuotes: true
//     }
// }));
module.exports = {
    //先找到每个入口(Entry),然后从各个入口分别出发,找到依赖的模块(Module),
    //然后生成一个Chunk(代码块),最后会把Chunk写到文件系统中(Assets)   
    entry: './src/main.js',
    output: {
        path: path.join(__dirname, 'dist'),//输出的文件夹,只能是绝对路径 
        //name是entry名字main,hash根据打包后的文件内容计算出来的一个hash值
        filename: '[name].[hash].js' //打包后的文件名
    },
    resolve: {
        //引入模块的时候,可以不用扩展名 
        extensions: [".js", ".less", ".json"],
        alias: {//别名
            "bootstrap": "bootstrap/dist/css/bootstrap.css"
        }
    },
    //表示监控源文件的变化,当源文件发生改变后,则重新打包
    watch: false,
    watchOptions: {
        ignored: /node_modules/,
        poll: 1000,//每秒钟询问的次数
        aggregateTimeout: 500//
    },
    //devtool: 'source-map',//单独文件,可以定位到哪一列出错了
    // devtool: 'cheap-module-source-map',//单独文件,体积更小,但只能定位到哪一行出错
    // devtool: 'eval-source-map',//不会生成单独文件,
    // devtool: 'cheap-module-eval-source-map',//不会生成单独文件 只定位到行,体积更小
    /*
    loader有三种写法
    use
    loader
    use+loader
    * */
    module: {
        rules: [
            {
                test: require.resolve('jquery'),
                use: {
                    loader: 'expose-loader',
                    options: '$'
                }
            },
            {
                test: /\.js/,
                use: {
                    loader: 'babel-loader',
                    query: {
                        presets: ["env", "stage-0", "react"]
                    }
                }
            },
            {
                //file-loader是解析图片地址,把图片从源位置拷贝到目标位置并且修改原引用地址
                //可以处理任意的二进制,bootstrap 里字体
                //url-loader可以在文件比较小的时候,直接变成base64字符串内嵌到页面中
                test: /\.(png|jpg|gif|svg|bmp|eot|woff|woff2|ttf)/,
                loader: {
                    loader: 'url-loader',
                    options: {
                        limit: 5 * 1024,
                        //指定拷贝文件的输出目录 
                        outputPath: 'images/'
                    }
                }
            },
            {
                test: /\.css$/,//转换文件的匹配正则
                //css-loader用来解析处理CSS文件中的url路径,要把CSS文件变成一个模块
                //style-loader 可以把CSS文件变成style标签插入head中
                //多个loader是有顺序要求的,从右往左写,因为转换的时候是从右往左转换
                //此插件先用css-loader处理一下css文件
                //如果压缩
                loader: cssExtract.extract({
                    use: ["css-loader?minimize"]
                })
                //loader: ["style-loader", "css-loader", "postcss-loader"]
            },
            {
                test: /\.less$/,
                loader: lessExtract.extract({
                    use: ["css-loader?minimize", "less-loader"]
                })
                //use: ["style-loader", "css-loader", "less-loader"]
            },
            {
                test: /\.scss$/,
                loader: sassExtract.extract({
                    use: ["css-loader?minimize", "sass-loader"]
                })
                // use: ["style-loader", "css-loader", "sass-loader"]
            },
            {
                test: /\.(html|htm)/,
                loader: 'html-withimg-loader'
            }
        ]
    },
    plugins: [
        //用来自动向模块内部注入变量
        // new webpack.ProvidePlugin({
        //     $: 'jquery'
        // }),
        new UglifyjsWebpackPlugin(),
        new CleanWebpackPlugin([path.join(__dirname, 'dist')]),
        //此插件可以自动产出html文件
        new HtmlWebpackPlugin({
            template: './src/index.html',//指定产的HTML模板
            filename: `index.html`,//产出的HTML文件名
            title: 'index',
            hash: true,// 会在引入的js里加入查询字符串避免缓存,
            minify: {
                removeAttributeQuotes: true
            }
        }),
        new CopyWebpackPlugin([{
            from: path.join(__dirname, 'public'),
            to: path.join(__dirname, 'dist', 'public')
        }]),
        cssExtract,
        lessExtract,
        sassExtract
    ],
    //配置此静态文件服务器,可以用来预览打包后项目
    devServer: {
        contentBase: './dist',
        host: 'localhost',
        port: 8000,
        compress: true,//服务器返回给浏览器的时候是否启动gzip压缩
    }
}

5. Summary

This article is more basic and can build a simple webpack configuration. Advanced and advanced will be introduced in subsequent articles, and I hope you will read the official API more and then summarize the output by yourself. Only by exporting the knowledge can you better memorize and learn.

6. Blog

Wei Ran Technology Blog

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324492624&siteId=291194637