最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Webpack4从入门到入土

    正文概述 掘金(心有林夕_)   2021-06-12   412

    Webpack

    一、Webpack简介

    1.1 Webpack是什么

    Webpack是一种前端资源构建工具,一个静态模块打包器。在Webpack看来,前端的所有资源文件都会作为模块处理,它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

    1.2 Webpack五个核心概念

    1.2.1 Entry

    ​ 入口(Entry)指示Webpack以哪个文件为入口起点开始打包,分析构建内部依赖图。

    1.2.2 Output

    ​ 输出(Output)指示Webpack打包后的资源bundles输出到哪里去,以及如何命名。

    1.2.3 Loader

    ​ Loader让Webpack能够去处理那些非JavaScript文件(webpack自身只理解JavaScript)

    1.2.4 Plugins

    插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。

    1.2.5 Mode

    ​ 模式(Mode)指示Webpack使用对应模式的配置。

    选项描述特点
    development会将process.env.NODE_ENV的值设为development。启用NamedChunksPluginNamedModulesPlugin能让代码本地调试运行的环境production会将process.env.NODE_ENV的值设为production。启用FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin能让代码优化上线运行的环境

    二、Webpack初体验

    2.1 运行指令

    ​ 开发环境:webpack ./src/index.js -o ./build/build.js --mode=development

    ​ 生产环境:webpack ./src/index.js -o ./build/build.js --mode=production

    ​ webpack会以./src/index.js为入口文件开始打包,打包后输出到./build/build.js,整体打包环境是开发/生产环境

    结论:

    1. webpack能处理js/json资源,不能处理css/img等其他资源
    2. 生成环境和开发环境将ES6模块编译成浏览器能识别的模块化
    3. 生成环境比开发环境多一个压缩js代码

    2.2 webpack配置

    webpack.config.js:webpack的配置文件。指示webpack干哪些活(当你运行webpack指令时,会加载里面的配置);
    ​ 所有构件工具都是基于nodejs平台运行的,模块化默认使用commonjs

    /*
        loader:1. 下载	2. 使用(配置loader)
        plugins:1.下载	2. 引入		3. 使用
    */
    // resolve用来拼接绝对路径的方法
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
    
    // 设置nodejs环境变量
    process.env.NODE_ENV = 'development';
    
    // 复用loader
    const commonCssLoader = [
        // use数组中loader执行顺序:从右到左,从下到上,依次执行。
        // 创建style标签,将js中的样式资源插入进行,添加到head中生效
        // 'style-loader',
        // 这个loader取代style-loader。作用:提取js中的css成单独文件
        MiniCssExtractPlugin.loader,
        // 将css文件变成commonjs模块加载js中,里面内容时样式字符串
        'css-loader',
        /*
          css兼容性处理:postcss --> postcss-loaderpost-preset-env
          帮postcss找到packet.json中browerslist里面的配置,通过配置加载指定的css兼容性样式
              "browserslist": {
                  // 开发环境 --> 设置node环境变量: process.env.NODE_ENV = 'development'
              "development": [
                "last 1 chrome version",
                "last 1 firefox version",
                "last 1 safari version",
               ],
               // 生产环境:默认是生产环境
               "production": [
                      ">0.2%",
                      "not dead",
                      "not op_mini all"
                ]
              }
            */
        // 使用loader的默认配置
        // 'post-loader',
        // 修改loader配置
        {
            loader: 'postcss-loader',
            options: {
                ident: 'postcss',
                plugins: () => [
                    // postcss的插件
                    require('postcss-preset-env')()
                ]
            }
        }
    ];
    
    module.exports = {
        // webpack配置
        // 入口起点
        entry: './src/index.js',
    
        // 输出
        output: {
            // 输出文件名
            filename: 'js/build.js',
            // 输出路径
            // __dirname nodejs的变量,代表当前文件的目录的绝对路径
            path: resolve(__dirname, 'build')
        },
    
        // loader的配置
        modules: {
            rules: [
                // 详细loader配置
                // 不同文件必须配置不同loader处理
                {
                    // 匹配哪些文件
                    test: /\.css$/,
                    // 使用哪些loader进行处理
                    use: [...commonCssLoader]
                },
                {
                    test: /\.less$/,
                    use: [
                        ...commonCssLoader,
                        // 将less文件编译成css文件
                        // 需要下载less-loader和less
                        'less-loader'
                    ]
                },
                {
                    // 处理样式中的图片资源 —— 默认处理不了html中的图片资源
                    test: /\.(jpg|png|gif)$/,
                    // 下载url-loader、file-loader
                    loader: 'url-loader',
                    options: {
                        // 图片大小小于8kb,就会被base64处理
                        // 优点:减少请求数量(减轻服务器压力)
                        // 缺点:图片提及会更大(文件请求速度更慢)
                        limit: 8 * 1024,
                        // 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
                        // 解析时会出问题:【object Module】
                        // 解决: 关闭url-loader的es6模块化,使用commonjs解析
                        esModule: false,
                        // 给图片进行重命名
                        // [hash: 10]取图片的hash值前10位
                        // [ext]取文件原来扩展名
                        name: '[hash:10].[ext]',
                        outputPath: 'imgs'
                    }
                },
                // 打包其他资源(除了html/js/css资源以外的资源)
                {
                    test: /\.html$/,
                    // 处理html文件中的img图片(负责引入img,从而能被url-loader进行处理)
                    loader: 'html-loader'
                },
                {
                    exclude: /\.(html|css|js|less|jpg|png|gif)$/,
                    loader: 'file-loader',
                    options: {
                        name: '[hash:10].[ext]',
                        outputPath: 'media'
                    }
                },
                // 正常来讲,一个文件只能被一个loader处理,当被多个loader处理,一定要指定loader执行的先后顺序:先执行eslint再执行babel
                {
                    /*
                        语法检查: eslint-loader eslint
                            注意:只检查自己写的源代码,第三方的库是不用检查的
                            设置检查规则:
                                package.json中eslintConfig中设置:
                                “eslintConfig”: {
                                    "extend": "airbnb-base"
                                }
                        airbnb --> eslint-config-airbnb-base	eslint-plugin-import	eslint
                    */
                    test: /\.js$/,
                    exclude: /node_modules/,
                    // 优先执行
                    enforce: 'pre',
                    loader: 'eslint-loader',
                    options: {
                        // 自动修复eslint的错误
                        fix: true
                    }
                },
                /*
                      js兼容性处理:babel-loader @babel/core @babel/preset-env
                          1. 基本js兼容性处理	==》 @babel/preset-env
                              问题:只能转换基本语法,如promise不能转换
                    2. 全部js兼容性处理	==》 @babel/polyfill
                          问题:我只要解决部分兼容性问题,但是所有兼容性代码全部引入,提及太大
                        3. 需要做兼容性处理的就做:按需加载	==》 core-js 
                */
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader',
                    options: {
                        // 预设:指示babel做怎么样的兼容性处理
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    // 按需加载
                                    useBuiltIns: 'usage',
                                    // 指定core-js版本
                                    corejs: { version: 3 },
                                    // 指定兼容性做到哪个版本的浏览器
                                    targets: {
                                        chrome: '60',
                                        firefox: '60',
                                        ie: '9',
                                        safari: '10',
                                        edge: '17'
                                    }
                                }
                            ]]
                    }
                }
            ]
        },
    
        // plugins配置
        plugins: [
            // 详细plugins配置
            // html-webpack-plugin —— 默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
            new HtmlWebpackPlugin({
                // 复制'./src/index.html'文件,并自动引入打包输出的所有资源(JS/CSS)
                template: './src/index.html',
                // 压缩html
                minify: {
                    // 移除空格
                    collapseWhitspace: true,
                    // 移除注释
                    removeComments: true
                }
            }),
            new MiniCssExtractPlugin({
                // 对输出的css文件重命名
                filename: 'css/build.css'
            }),
            // 压缩css
            new OptimizeCssAssetsWebpackPlugin()
        ],
    
        // 模式
        mode: 'development',
        // mode: 'production',
    
        // 开发服务器devServer:用来自动化(自动编译、自动打开浏览器、自动刷新浏览器)
        // 特点:只会在内存中编译打包,不会有任何输出
        // 启动devServer指令为:`npx webpack-dev-server`
        devServer: {
            // 项目构建后路径
            contentBase: resolve(__dirname, 'build'),
            // 启动gzip压缩
            compress: true,
            // 端口号
            port: 3000,
            // 自动打开浏览器
            open: true
        }
      }
    

    三、Webpack性能优化

    3.1 开发环境性能优化

    3.1.1 优化打包构建速度

    ​ HMR:hot module replacement 热模块替换/模块热替换

    ​ 作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度。

    ​ 样式文件:可以使用HMR功能:因为style-loader内部实现了

    ​ js文件:默认不能使用HMR功能。 --> 需要修改js代码,添加支持HMR功能的代码

    ​ 注意:HMR功能对js的处理,只能处理非入口文件的其他文件。

    if(module.hot){module.hot.accept('文件路径', function(){...})}

    ​ html文件:默认不能使用HMR功能,同时会导致html文件不能热更新。(不用做HMR功能)

    ​ 解决:修改entry入口,将html文件引入

    entry: ['./src/index.html']
    devServer: {
    	// 开启HMR功能
    	hot: true,
    }
    

    3.1.2 优化代码调试

    ​ source-map:一种提供源代码到构建后代码映射的技术(如果构建后代码出错了,通过映射可以追踪源代码错误)

    [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

    source-map:外部

    ​ ----> 错误代码准确信息 和 源代码的错误位置

    inline-source-map:内联;只生产一个内联source-map

    ​ ----> 错误代码准确信息 和 源代码的错误位置

    hidden-source-map:外部;

    ​ ----> 错误代码错误原因,但是没有错误位置;不能跟踪源代码错误,只能提示到构建后代码的错误位置

    eval-source-map:内联;每一个文件都生产对应的source-map,都在eval里

    ​ ----> 错误代码准确信息 和 源代码的错误位置

    nosources-source-map: 外部

    ​ ----> 错误代码准确信息但是没有任何源代码

    cheap-source-map:外部

    ​ ----> 错误代码准确信息 和 源代码的错误位置;只能精确到行

    cheap-module-source-map:外部

    ​ ----> 错误代码准确信息 和 源代码的错误位置;只能精确到行

    ​ ----> module会将loader的source map加入

    内联和外部的区别:1. 外部生成了文件,内联没有;2. 内联构建速度更快

    开发环境:速度快,调试更友好

    ​ 速度快:eval>inline>cheap>...

    ​ eval-cheap-source-map

    ​ eval-source-map

    ​ 调试更友好

    ​ source-map

    ​ cheap-module-source-map

    ​ cheap-source-map

    ​ --> eval-source-map / eval-cheap-module-source-map

    生产环境:源代码要不要隐藏?调试要不要更友好?

    ​ 内联会让代码体积变大,所以在生产环境不用内联

    ​ nosources-source-map 全部隐藏

    ​ hidden-source-map 只隐藏源代码,会提示构建后代码错误信息

    --> source-map / cheap-module-source-map

    module.exports = {
      ...,
    	devtool: 'source-map';
    }
    

    3.2 生产环境性能优化

    3.2.1 优化打包构建速度

    3.2.1.1 oneof
    const { resolve } = require('path');
    
    const commonCssLoader = [
        MiniCssExtractPlugin.loader,
        'css-loader',
    
        {
            loader: 'postcss-loader',
            options: {
                ident: 'postcss',
                plugins: () => [
                    // postcss的插件
                    require('postcss-preset-env')()
                ]
            }
        }
    ];
    
    module.exports = {
        entry: './src/index.js',
    
        output: {
            filename: 'js/build.js',
            path: resolve(__dirname, 'build')
        },
    
        modules: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    enforce: 'pre',
                    loader: 'eslint-loader',
                    options: {
                        fix: true
                    }
                },
                {
                    // 一个文件只会匹配一个loader,匹配到了不会向下继续匹配
                    oneof: [
                        {
                            test: /\.css$/,
                            use: [...commonCssLoader]
                        },
                        {
                            test: /\.less$/,
                            use: [
                                ...commonCssLoader,
                                'less-loader'
                            ]
                        },
                        {
                            test: /\.(jpg|png|gif)$/,
                            loader: 'url-loader',
                            options: {
                                limit: 8 * 1024,
                                esModule: false,
                                name: '[hash:10].[ext]',
                                outputPath: 'imgs'
                            }
                        },
                        {
                            test: /\.html$/,
                            loader: 'html-loader'
                        },
                        {
                            exclude: /\.(html|css|js|less|jpg|png|gif)$/,
                            loader: 'file-loader',
                            options: {
                                name: '[hash:10].[ext]',
                                outputPath: 'media'
                            }
                        },
    
                        {
                            test: /\.js$/,
                            exclude: /node_modules/,
                            loader: 'babel-loader',
                            options: {
                                presets: [
                                    [
                                        '@babel/preset-env',
                                        {
                                            useBuiltIns: 'usage',
                                            corejs: { version: 3 },
                                            targets: {
                                                chrome: '60',
                                                firefox: '60',
                                                ie: '9',
                                                safari: '10',
                                                edge: '17'
                                            }
                                        }
                                    ]]
                            }
                        }
                    ]
                }
            ]
        },
        // mode: 'development',
        mode: 'production',
    
    }
    
    3.2.1.2 babel缓存
    /*
        babel缓存 --> 第二次打包构建速度更快
            cacheDirectory: true
    */
    module.exports = {
        entry: './src/index.js',
    
        output: {
            filename: 'js/build.js',
            path: resolve(__dirname, 'build')
        },
    
        modules: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader',
                    options: {
                        presets: [[
                            '@babel/preset-env',
                            {
                                useBuiltIns: 'usage',
                                corejs: { version: 3 },
                                targets: {
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]],
                        // 开启babel缓存
                        // 第二次构建时,会读取之前的缓存
                        cacheDirectory: true
                    }
                }
            ]
        }
    }
    
    3.2.1.3 多进程
    module.exports = {
        entry: './src/index.js',
    
        output: {
            filename: 'js/build.[contenthash:10].js',
            path: resolve(__dirname, 'build')
        },
    
        modules: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: [
                        /*
                            开启多进程打包
                            进程启动大概为600ms,进程通信也有开销
                            只有工作消耗时间比较长,才需要多进程打包
                        */
                        {
                            loader: 'thread-loader',
                            options: {
                                workers: 2	// 开启2个进程
                            }
                        },
                        {
                            loader: 'babel-loader',
                            options: {
                                presets: [[
                                    '@babel/preset-env',
                                    {
                                        useBuiltIns: 'usage',
                                        corejs: { version: 3 },
                                        targets: {
                                            chrome: '60',
                                            firefox: '60',
                                            ie: '9',
                                            safari: '10',
                                            edge: '17'
                                        }
                                    }
                                ]],
                                // 开启babel缓存
                                // 第二次构建时,会读取之前的缓存
                                cacheDirectory: true
                            }
                        }
                    ]
                }
            ]
        }
    }
    
    3.2.1.4 externals
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        entry: './src/index.js',
        output: {
            // [name] 取文件名
            filename: 'js/[name].[contenthash:10].js',
            path: resolve(__dirname, 'build')
        },
        ...
        mode: 'production',
        externals: {
            // 拒绝jQuery被打包 -- npm包名
            // 需要手动引入cdn - jQuery
            jquery: 'jQuery'
        }
    }
    
    3.2.1.5 dll
    /*
        使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
            当你运行webpack时,默认查找webpack.comfig.js配置文件
            需要运行:webpack.dll.js文件
            --> webpack --config webpack.dll.js
    */
    const { resolve } = require('path');
    const webpack = require('webpack');
    
    module.exports = {
        entry: {
            // 最终打包生成的[name] --> jquery
            // ['jquery'] --> 要打包的库是jquery
            jquery: ['jquery']
        },
        output: {
            filename: '[name].js',
            path: resolve(__dirname, 'dll'),
            library: '[name]_[hash]',	// 打包库里面向外暴露出去的内容叫什么名字
        },
        plugins: [
            // 打包生成一个manifest.json --> 提供和jquery映射
            new webpack.DllPlugin({
                name: '[name]_[hash]',	// 映射库的暴露的内容名称
                path: resolver(__dirname, 'dll/manifest.json')	// 输出文件路径
            })
        ],
        mode: 'production'
    }
    
    
    // webpack.config.js
    
    const webpack = require('webpack');
    const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
    plugins: [
        ...
        new webpack.DllReferencePlugin({
            //	告诉webpack哪些库不参与打包,同时使用时的名称也得变
            manifest: resolve(__dirname, 'dll/manifest.json')
        }),
        // 将某个文件打包输出去,并在html中自动引入该资源
        new AddAssetHtmlWebpackPlugin({
            filepath: resolve(__dirname, 'dll/jquery.js')
        })
    ]
    

    3.2.2 优化代码运行的性能

    3.2.2.1 文件缓存
    /*
        文件资源缓存 --> 让代码上线运行缓存更好使用
            问题:强缓存命中,无法获取最新资源
            hash:每次webpack构建时会生产唯一的hash值
                问题:因为js和css同时使用一个hash值,如果重新打包,会导致所有缓存失效(无论改动几个文件)
            chunkhash:根据chunk生产的hash值,如果打包来源于同一个chunk,那么hash值就一样
                问题:js和css的hash值还是一样的,因为css时在js中被引入的,所以同属于一个chunk
            contenthash:根据文件内容生产hash值,不同文件hash值一定不一样
    */
    module.exports = {
        entry: './src/index.js',
    
        output: {
            // filename: 'js/build.[hash:10].js',
            // filename: 'js/build.[chunkhash:10].js',
            filename: 'js/build.[contenthash:10].js',
            path: resolve(__dirname, 'build')
        },
        ...
    }
    
    3.2.2.2 tree shaking
    /*
    	tree shaking:去除无用代码
    		前提:1. 必须使用ES6模块化
    				 2. 开启production环境
    		作用:减少代码体积
    		
    		在package.json中配置
    			"sideEffects": false	所有代码都没有副作用(都可以进行tree shaking)
    			问题:可能会把css、/@babel/polyfill文件干掉
    			"sideEffects": ["*.css", "*.less"]
    */
    
    3.2.2.3 code split
    // demo1
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        // 单入口
        // entry: './src/index.js',
        entry: {
            // 多入口:输出多个bundle
            index: './src/index.js',
            test: './src/test.js'
        },
        output: {
            // [name] 取文件名
            filename: 'js/[name].[contenthash:10].js',
            path: resolve(__dirname, 'build')
        },
        ...
    }
    
    // demo2
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        // 单入口
        //entry: './src/index.js',
        entry: {
            // 多入口:输出多个bundle
            index: './src/index.js',
            test: './src/test.js'
        },
        output: {
            // [name] 取文件名
            filename: 'js/[name].[contenthash:10].js',
            path: resolve(__dirname, 'build')
        },
        /*
              1. 可以将node_modules中代码单独打包一个chunk最终输出
              2. 自动分析,多入口文件中有没有公共的文件,如果有会打包成一个单独的chunk
        */
        optimization: {
            splitChunks: {
                chunks: all
            }
        }
    	...
    }
    
    // demo3
    /*
        基于webpack配置optimization,通过js代码,让某个文件被单独打包成一个chunk
        import动态导入语法:能将某个文件单独打包
    */
    // 限定名字
    import(/*webpackChunkName: 'test'*/'./test')
        .then(result => { })
        .catch(() => { })
    
    3.2.2.4 lazy loading
    // 基于3.2.1.4代码分割实现懒加载
    document.getElementById('btn').onclick = function(){
      // 懒加载:当文件需要使用时才加载
      // 预加载 prefetch:会在使用之前,提前加载js文件
      // 正常加载可以认为是并行加载(同一时间加载多个文件)
      // 预加载会等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
      import(/*webpackChunkName: 'test', webpackPrefetch: true*/'./test')
        .then(({mul}) => {
          console.log(mul(4,5))
        })
    }
    
    3.2.2.5 PWA
    /*
        PWA:渐进式网络开发应用程序(离线可访问)
            workbox -->	workbox-webpack-plugin
    */
    
    const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
    module.exports = {
        ...
        plugins: [
    		...
        /*
            1. 帮助serviceworker快速启动
            2. 删除旧的serviceworker
        	
            生成一个serviceworker配置文件
        */
        new WorkboxWebpackPlugin.GenerateSW({
            clientsClaim: true,
            skipWaiting: true
        })
      ]
    }
    
    /*
        1. eslint不认识window、navigator全局变量
            解决:需要修改package.json中eslintConfig配置
                "env": {
                    "brower": true	// 支持浏览器端全局变量
                }
       2. sw代码必须运行在服务器上
              --> nodejs
              --> npm i serve -g
                        serve -s build	启动服务器,将build目录下的所有资源作为静态资源暴露出去
    */
    // index.js 入口文件
    if ('serviceWorker' in navigator) {
        window.addEventListener('load', () => {
            navigator.serviceWorker
                .register('/service-worker.js')
                .then(() => { })
                .catch(() => { })
        })
    }
    

    四、webpack配置详解

    4.1 entry

    /*
        entry: 入口起点
            1. string --> './src/index.js'
                打包形成一个chunk,输出一个bundle文件。
                此时chunk的默认名称是main
        2. array	-->	['./src/js', './src/add.js']
            多入口
            所有入口文件最终只会形成一个chunk,输出一个bundle文件
                --> 一般用于HMR功能中让html热更新生效
        3. object
            多入口
            有几个入口文件就形成几个chunk,输出几个bundle文件
            此时chunk的名称是key
            --> 特殊用法	3里面包含1+2两种形式
    */
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        // entry: './src/index.js',
        // entry: ['./src/index.js', './src/add.js'],
        entry: {
            // index: './src/index.js',
            index: ['./src/index.js', './src/add.js'],
            add: './src/add.js'
        },
        output: {
            filename: '[name].js'
        path: resolve(__dirname, 'build')
        },
        plugins: [new HtmlWebpackPlugin()],
        mode: 'development'
    }
    

    4.2 output

    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        entry: './src/index.js',
        output: {
            // 文件名称(指定名称+目录)
            filename: 'js/[name].js'
        // 输出文件目录(将来所有资源输出的公共目录)
        path: resolve(__dirname, 'build')
      	// 所有资源引入公共路径前缀:	'imgs/a.jpg' --> '/imgs/a.jpg'
      	publicPath: '/',
            chunkFilename: '[name]_chunk.js',	// 非入口chunk的名称
            // library: '[name]',	// 整个库向外暴露的变量名 + 一般结合dll一起使用
            // libraryTarget: 'window'	// 变量名添加到哪个上 browser
            // libraryTarget: 'global'	// 变量名添加到哪个上 node
            // libraryTarget: 'commonjs'	// 模块化语法
    
        },
        plugins: [new HtmlWebpackPlugin()],
        mode: 'development'
    }
    

    4.3 module

    
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: 'js/[name].js'
        path: resolve(__dirname, 'build')
        },
        module: {
            rules: [
                // loader的配置
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.js$/,
                    // 排除node_modules下的js文件
                    exclude: /node_modules/,
                    // 只检查src下的js文件
                    include: resolve(__dirname, 'src'),
                    // 优先执行
                    enfore: 'pre',
                    // 延后执行
                    // enfore: 'post',
                    // 单个loader使用loader
                    loader: 'eslint-loader',
                    options: {}
                },
                {
                    // 一下配置只会生效一个
                    oneof: []
                }
    
            ]
        },
        plugins: [new HtmlWebpackPlugin()],
        mode: 'development'
    }
    

    4.4 resolve

    
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: 'js/[name].js'
        path: resolve(__dirname, 'build')
        },
        module: {
            rules: [
                // loader的配置
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
            ]
        },
        plugins: [new HtmlWebpackPlugin()],
        mode: 'development',
        // 解析模块的规则
        resolve: {
            // 配置解析模块路径别名: 简写路径
            alias: {
                $css: resovle(__dirname, 'src/css')
            },
            // 配置省略文件路径的后缀名
            extensions: ['js', 'json', 'css', 'jsx'],
            // 告诉webpack解析模块是去找哪个目录
            modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
        }
    }
    

    4.5 devServer

    
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: 'js/[name].js'
        path: resolve(__dirname, 'build')
        },
        module: {
            rules: [
                // loader的配置
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
            ]
        },
        plugins: [new HtmlWebpackPlugin()],
        mode: 'development',
        devServer: {
            // 运行代码的目录
            contentBase: resolve(__dirname, 'build'),
            // 见识contenBase目录下的所有文件,一旦文件变化就会reload
            watchContentBase: true,
            watchOptions: {
                // 忽略文件
                ignored: /node_modules/
            },
            // 启动gzip压缩
            compress: true,
            // 端口号
            port: 5000,
            // 域名
            host: 'localhost',
            // 自动打开浏览器
            open: true,
            // 开启HMR功能
            hot: true,
            // 不要显示启动服务器日志信息
            clientLogLevel: 'none',
            // 除了一些基本启动信息以外,其他内容都不要显示  
            quiet: true,
            // 如果出错了,不要全屏提示
            overlay: false,
            // 服务器代理 --> 解决开发环境跨域问题
            proxy: {
                // 一旦devServer(5000)服务器接收到/api/xxx的请求,就会把请求转发到另一个服务器
                '/api': {
                    target: 'http://localhost:3000',
                    // 发送请求时,请求路径重写:将/api/xx	-->	/xxx;(去掉/api)
                    pathRewrite: {
                        '^/api': ''
                    }
                }
            }
        }
    }
    

    4.6 optimization

    
    const { resolve } = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const TerserWebpackPlugin = require('terser-webpack-plugin');
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: 'js/[name].js'
        path: resolve(__dirname, 'build')
        },
        module: {
            rules: [
                // loader的配置
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
            ]
        },
        plugins: [new HtmlWebpackPlugin()],
        mode: 'production',
        optimization: {
            splitChunks: {
                chunks: 'all',
                // 以下为默认值
                /*
                 minSize: 30 * 1024,	// 分割的chunk最小为30kb
                 maxSize: 0,	// 最大没有限制
                 minChunks: 1,	// 要提取的chunk最少被引用1次
                 maxAsyncRequests: 5,	// 按需加载时并行加载的文件最大数量
                 maxInitialRequests: 3,	// 入口js文件最大并行请求数量
                 automaticNameDelimiter: '~',	// 名称链接符
                 name: true,	// 可以使用命名规则
                 cacheGroups: {
                   // 分割chunk的组
                   // node_modules文件会被打包到wendors组的chunk中。	--> vendors~xxx.js
                   // 满足上面的公共规则,如:大小超过30kb,至少被引用一次
                   vendors: {
                     test: /[\\/]node_modules[\\/]/,
                     // 优先级
                     priority: -10
                   },
                   default: {
                       // 要提取的chunk最少被引用2次
                     minChunks: 2,
                     // 优先级
                     priority: -20,
                     // 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用
                     reuseExistingChunk: true
                   }
                 }
                 */
            },
            // 将当前模块的记录其他模块的hash单独打包为一个文件runtime
            // 解决:修改a文件导致b文件的contenthash变化
            runtimeChunk: {
                name: entrypoint => `runtime-${entrypoint.name}`
            },
            minimizer: {
                // 配置生成环境的压缩方案:js和css
                new TerserWebpackPlugin({
                    // 开启缓存
                    cache: true,
                    // 开启多线程打包
                    parallel: true
            // 启动source-map
            sourceMap: true
                })
            }
        }
    }
    

    起源地下载网 » Webpack4从入门到入土

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元