webpack基础

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。 

源 - webpack - bundle 

 

1、核心概念

  1.1、Entry:指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图

  1.2、Output:指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名

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

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

  1.5、Mode:development、production

 

2、webpack能处理js/json资源,不能处理css/img等其他资源,也不能将es6语法转成es5以下

 

3、loader:style-loader、css-loader、less-loader、url-loader(在webpack5中官方文档已经改成asset)、html-loader等

                use: [                            //use数组是倒序加载,所以先写style添加,再写css
                    //创建style标签,将js中样式资源插入,添加到head
                    'style-loader',
                    //将css文件以字符串编程commonjs模块加载到js中,
                    'css-loader'
                ]

如果需要不同的loader需要加载不同的规则,匹配不同的文件

若background使用图片,可以用url-loader,对图片base64处理,减小服务器压力,但是图片体积会更大,导致文件请求速度更慢,所以一般对小图片处理,10kb左右

 

4、plugins:HtmlWebPlugin:生成一个 HTML5 文件, 在 body 中使用script标签引入你所有 webpack 生成的 bundle

 

5、devServer实现热更新,只会在内存编译,不会有任何输出

 

6、生产环境配置:

  6.1:将css文件单独提取:minicss-extract-plugin

  6.2:兼容性处理:postcss-loader、post-preset-env,比如内部的browserslist自适应配置浏览器,注意,默认环境变量为生产模式,若为开发模式,需要手动改变NODE_ENV

  6.3:压缩css:css-minimizer-webpack-plugin

  6.4:js语法检查:eslint-loader、eslint;为了不检查第三方库js,只检查自己的,还需要exclude:/modules/;还需要在package.json添加检查eslintConfig规则:airbnb

  6.5:基本js兼容性问题(ES6):babel-loader、@babel/preset-env、@babel/core

  6.6:全部js兼容(promise等):@babel/polyfill

  6.7:部分兼容性问题(减小体积):core-js

  6.8:JS压缩:生产环境UglifyJsPlugin自动压缩

  6.9:HTML压缩:HtmlWebpackPlugin:minify:collapseWhitespace:true,removeComments:true

  6.10:复用loader:将重复使用的loader放在数组内,引用是运用rest扩展 ...

  6.11:当一种文件被多个loader执行的时候,需要指定顺序,如先执行eslint,再到babel。enforce:‘pre’,优先执行

  6.12:webpack4:html-loader、url-loader使用的是es6module,要统一配置:在html-loader下配置esModule:false

 

7、性能优化配置:

  7.1:开发环境性能优化:打包构建速度优化、代码调试优化

    7.1.1:HMR模块热替换(hot module replacement),devServer内打开hot:true(webpack5默认打开)。单独打包热更新,而不是全部重新打包(样式文件可以、js默认不可以,可以在js内添加hot监听js变化、html默认不可以,但是可以改版entry入口实现

    7.1.2:source-map:源代码转构建代码的映射信息。如果构建后代码错误,可以通过映射信息找到源代码修改。该为基础命令,生成在外部  .map

       还有如:inline-source-map在js内内联生成map,统一放在js最后、hidden-source-map外部生成,只有构建后代码错误位置,隐藏源代码、eval-source-map每个文件生成内联sourcemapurl,都在eval函数中、nosource-source-map有错误信息,没有位置,隐藏源代码cheap-[module]-source-map等配置

          开发环境(速度要快(eval>inline>cheap...eval-cheap-source-map,调试要友好(source-map>cheap-module-source-map))一般用eval-source-map和eval-cheap-module-source-map

       生产环境(源代码是否需要隐藏(nosource-source-map和hidden-source-map),调试是否需要友好)内联让体积变大,一般不用,主要用source-map和cheap-module-source-map

 

  7.2:生产环境优化:打包构建速度优化、代码运行性能优化

    7.2.1:oneOf:每个文件只对应一个loader,不用多次重复扫描匹配loader,但是要注意,同一个文件不能有两个不同rule,不同loader,如js不能即eslint,又babel,把其中一个提出去,也需要注意先后顺序,是否先oneOf内

    7.2.2:缓存优化:生产环境没有HMR,要实现热更新需要开启babel缓存

       又由于缓存的原因,若修复bug或改变样式后,无法重新加载新内容,而是浏览器直接读取缓存旧数据,

       所以可以在更新的内容文件名加上hash(hash:10十位哈希),让浏览器重新加载。

       但是又有新问题,如果都用hash的话,一个css改动,同hash的js也会重新缓冲,会造成资源浪费

       引入chunkhash:根据chunk生成hash,若打包来自同一chunk,则hash相同

       但还是有问题,css是通过import到js,若改css,则js也改变,所以他们都属于同一个chunk,hash依旧相同

       使用contenthash:根据内容生成不同hash

    7.2.3:tree shaking:去除不使用的代码(只引入所需代码)。前提:使用es6模块化,开启production就会默认开启。若配合package.json中"sideEffects":false(即所有代码都可以tree shaking),css会除去。可以写成"sideEffects": ["*.css"]

    7.2.4:代码分包/分割code split:

       7.2.4.1、单入口,单页面 / 多入口文件,多页面,但是页面越多,越不好改,不好添加

       7.2.4.2、splitChunks:根据条件自动拆分chunks:optimization下,如在node_modules中、新chunk大于20kb、多入口文件有没有公共chunk等

       7.2.4.3、开发中,单入口会比较多。可以在 js 中动态导入,让某个别的 js 文件单独打包成chunk

    7.2.5:懒加载(js懒加载,不是图片):达到某些条件再加载,前提条件就是上述第三种类型的代码分割,其实也是动态导入,比如点击一个按钮后在import

       预加载prefetch 提前加载文件,相比于正常加载(并行加载同一文件),预加载等其他资源加载完了,预加载的大文件再加载,让其他资源先加载

    7.2.6:PWA(Progressive Web App渐进式网络开发应用程序)离线访问上一次已经加载好的内容。用得不多了。。

    7.2.7:多进程打包:优化打包速度。thread-loader,一般给babel用。因为每个 worker 都是一个独立的 node.js 进程,其开销大约为 600ms 左右。同时会限制跨进程的数据交换,只在耗时的操作中使用此 loader,所以一般放在js打包中,且为大js

    7.2.8:externals:防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖,如cdn的jquery

    7.2.9:dll(动态链接库):将不同的库打包成不同的chunk,不必像node_modules里全部打包成一个。由于新建了webpack.dll.js包含DllPlugin,但是打包的时候默认运行webpack.config.js,需要修改打包配置为webpack.dll.js(webapck --config webpack.dll.js)生成库。生成完成之后再用webpack.config.js内的DllReferencePlugin,告诉其不需要打包该库,引用(add-asset-html-webpack-plugin)即可

 

8、详细配置

  8.1:entry:入口起点

    8.1.1. 当入口为string --> './src/index.js',单入口,打包形成一个chunk,输出一个bundle文件。此时chunk的名称默认是main

    8.1.2. 当入口为array -->[ './src/index.js',  './src/add.js']。多入口,最后只生成一个chunk,输出一个bundle。主要为HMR服务,让html热更新生效

    8.1.3. 当入口为object -->{index: './src/index.js',  add: './src/add.js'}  key: value。多入口,有几个入口则生成几个chunk与对应的多个bundle,默认名称为key

    以上可以结合使用,利于整合

 

  8.2:output:输出

    output: {
        //文件名称(指定名称+目录)
        filename: 'js/built[name].js',
        //输出文件目录,所有资源的公共目录
        path: path.resolve(__dirname, 'build'),
        //所有资源的公共路径前缀,生产环境中服务器寻找可能需要前缀/,并不是本地路径
        // publicPath:'/',
        //非入口chunk名称,如import、optimization
        chunkFilename: 'js/[name]_chunk.js',
        //全局暴露
        library:'[name]',
        //变量名添加到哪个上,如browser,node等
        libraryTarget:'window',
        clean:true
    },

 

  8.3:module:

    module: {
        rules: [{
            test: /\.css$/,
            //多个loader
            use: ['style-loader', 'css-loader']
        },{
            test: /\.js$/,
            //不检查
            exclude: /node_modules/,
            //只检查
            include:path.resolve(__dirname,'src'),
            //优先执行
            enforce:'pre',
            //延迟执行
            enforce:'post',
            //若不写,则中间执行
            //单个loader
            loader:'eslint-loader',
        },{
            //配置只生效一个
            oneOf:[]
        }]
    },

 

  8.4:resolve:解析模块规则

    resolve:{
        //配置解析路径别名
        alias:{
            //css绝对路劲,方便查找,import的时候写$即可
            $css:path.resolve(__dirname,'src/css'),
        },
        //配置省略路径的后缀名,按顺序查找
        extensions:['.js','.json','.css'],
        //告诉webpack解析模块去哪找,省去一层层查找
        modules:[path.resolve(__dirname,'../../node_modules')]
    }

 

  8.5:devServer:开发环境内调试

    devServer: {
        //代码目录
        static: {
            directory: path.join(__dirname, 'public'),
        },
        //启动gzip压缩,让服务器启动更快
        compress: true,
        port: 9000,
        host: 'localhost',
        //自动打开浏览器
        open: true,
        //开启HMR
        hot: true,
        //简介启动信息
        quiet: true,
        //出错全屏提示
        overlay: true,
        //服务器代理,解决跨域
        proxy:{
            //请求转发
            '/api':{
                target:'http://localhost:3000',
                //发送请求路径重写,将/api/xxx转成/xxx,即去掉api
                pathRewrite:{
                    '^/api':''
                }
            }
        }
    },

 

  8.6:optimization:

    optimization: {
        splitChunks: {
            chunks: 'all',

            //以下为默认值
            //分割的chunk最小为30kb
            minSize: 30 * 1024,
            //最大无限制
            maxSize: 0,
            //要提取的chunk最少被引用一次
            minChunks: 1,
            //按需加载时并行加载的文件最大数量
            maxAsyncRequests: 5,
            //入口js文件最大并行请求数量
            maxInitialRequests: 3,
            //名称连接符号
            automaticNameDelimiter: '~',
            //可以使用命名规则
            name: true,
            //分割chunk组
            cacheGroups: {
                //node_modules文件打包到vendors组的chunk中,vendors~xxx.js
                //这里的打包满足上面的规则
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    //打包优先级-10
                    proprity: -10
                },
                //多入口同一依赖
                default: {
                    //要提取的chunk最少引用2次
                    minChunks: 2,
                    //打包优先级-20
                    proprity: -20,
                    //如果当前要打包的模块和之前已经提取的是同一个,就会直接复用,不重新打包
                    reuseExistingChunk: true
                }
            }
        },
        //将当前模块记录其他模块的hash单独打包为一个文件,该文件叫runtime
        //就是生成了一个中间件记录hash保证contenthash不全更新,不影响其他文件缓存
        runtimeChunk: {
            name: entrypoint => `runtime-${entrypoint.name}`
        },
        //配置生产环境压缩方案:js和css
        minimizer: [
            new TerserPlugin({
                //开启缓存
                cache: true,
                //启动sourceMap
                sourceMap: true,
                //webpack5上面两个不用写
                //开启多进程打包
                parallel: true,
            }),
        ],
    },

 

webpack5:

 

posted @ 2021-09-14 21:55  Jacky02  阅读(59)  评论(0)    收藏  举报