webpack4小记

235 阅读7分钟

webpack是什么?

  • Webpack模块打包工具,它会分析模块之间的依赖关系,然后使用loaders处理它们,最后生成一个优化并合并后的静态资源。

webpack之entry

  • 可以通过在 webpack 配置中配置 entry 属性,来指定一个入口起点(或多个入口起点)。
  • 单文件写法
        entry: './path/to/my/entry/file.js'
  • 多文件形式打包(object形式)
       entry: {
        app: './src/app.js',
        vendors: './src/vendors.js'
      }

webpack之output

  • 配置 output 选项可以控制 webpack如何向硬盘写入编译文件。

    注意,即使可以存在多个入口起点,但只指定一个输出配置,属性功能如下。

  • filename
        filename:'[name].js'   //导出的文件名字
  • path
        path:path.resolve(__dirname,'dist')    //导出的文件存放位置
  • publicPath
        publicPath:'http:cdn.com.cn'   //给每个js文件设置一个公共头部,打包出来后每个文件就是 http:cdn.com.cn/[name].js

webpack之热更新

1.webpack-dev-server

不刷新浏览器,不输出文件,而是放在内存中,使用HotModuleReplacementPlugin插件

  • 只用于开发环境中:devServer,开启一个web服务器,简要配置已以及属性功能如下
     devServer:{
            contentBase:'./dist', //打开文件的目录
            open:true,  //自动打开浏览器
            port:8010, // 打开端口号
            proxy:{
                '/api':'http://localhost:30000' //反向代理,解决跨域问题
            },
            hot:true, //自动刷新
            hotOnly:true 
        },

2.webpack-dev-middleware

  • 将webapck输出文件传输给服务器,适用于灵活的定制场景

3.webpack热更新原理的实现

A->B是首次编译过程。1—>2—>3->4 是文件改动后热更新过程

webpack之mode

  • development:开发模式,不进行压缩代码
  • production: 生产模式,会压缩代码

webpack之devtool:

  • 是一个帮助我们调试的工具,可以选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度,官网链接
  • 配置格式以及部分source map值说明如下:
        devtool:'cheap-module-eval-source-map',
         /**
             * none不提示哪里错了
             * source-map 是一个映射关系,定位错误。
             * inline-source-map 在行内添加映射关系
             * cheap-source-map 提高打包速度,只报业务代码错误,错误只是精确到某一行
             * cheap-module-source-map 包含业务代码和第三方插件错误都会报,错误只是精确到某一行
             * eval 执行效率最快,不适合复杂的代码
         */
  • 最佳实践 传送门
    • 开发环境
         devtool:'cheap-module-eval-source-map',
    
    • 生产环境
         devtool:'cheap-module-source-map',
    

webpack之plugins

  • plugins是插件,用来强大webpack的功能,通俗的来说就是可以在webpack运行到某些时刻自动的帮你干一些事情。

    注:使用plugins前记得先 require() 入相应的plugin

  • 常用的plugins如下:

  • 举例:
     plugins: [
            new CleanWebpackPlugin(), //在每一次打包之前把打包目录清空,如将dist文件清空
            new HtmlWebpackPlugin({ //会在打包结束后,自动生成一个html文件,并把打包的js自动引入到文件中
                template:'src/index.html'
            })
        ],

webpack之loaders

  • webpack 可以使用 loaders 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源,他是一个函数。loaders有很多,常用的如下:

  • 这里简要的举例几个常用的。

    • babel-loader

      注:业务代码开发记得在打包入口文件中引入import "@babel/polyfill",如果是开发一个组件库或者一个类库则不需要,因为polyfill的方法注入是全局的。可以使用@babel/plugin-transform-runtime 插件,会以闭包的形式引入;

           { 
            test: /\.js$/, //指定匹配规则
            /**
             * exclude:表示不会对node_modules里面的东西进行转义为es6,加快打包速度
             */
            exclude: /node_modules/, 
            loader: "babel-loader", //使用的loader名
            options:{ //这部分也可以放在.babelrc文件中
              "presets": [
                [
                  "@babel/preset-env",
                  {
                    /**
                     * 指定版本进行es6->es5
                     */
                    "targets": {
                      "edge": "17",
                      "firefox": "60",
                      "chrome": "67",
                      "safari": "11.1"
                    },
                    "useBuiltIns": "usage" //只把需要的业务代码进行转化,可以大大的减小打包体积
                  }
                ],
                "@babel/preset-react" //用于react项目
              ]
            }
        }
    
    • url-loader
      • url-loader和file-loader功能是相似的,可以处理图片和字体,url-loader可以设置较小的资源自动base64
    {
            test:/\.(png|jpg|gif)$/,
            use:{
                loader:'url-loader',
                options:{
                    /**
                     * name:打包后的图片名字
                     * limit:将小于2048kb的图片转为base64,可以较少网络请求,将大于2048kb的图片放入到images/
                     * outputPath:图片文件打包后的存放目录
                     */
                    name:'[name].[ext]',
                    outputPath:'images/',
                    limit:2048
                }
            }
        },
    
    • postcss-loader
      • 自动给css添加浏览器前缀,比如-webkit-。可以直接在option中配置,也可以在postcss.config.js中配置。 以下示例在postcss.config.js中配置
      module.exports = {
          plugins:[require('autoprefixer')({
              overrideBrowserslist: [
                'last 10 Chrome versions',
                'last 5 Firefox versions',
                'Safari >= 6', 
                'ie> 8'
              ] 
           })]
        }
      
    • css-loader
      • css-loader用于将.css文件,并转化为common.js文件。style-loader将样式通过<style>标签插入到head中
        {
                test: /.css$/,
                use: [
                    'style-loader',//loader 链式调用的顺序是从右到左,先是 css-loader, 再是 style-loader
                    'css-loader'
                ]
            },
            {
                test: /.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            }
        }
    

    webpack之文件监听

    缺陷:每次更新后都需要开发者手动更新浏览器

    • 文件监听是指在发现源代码发生变化是,自动构建出新的输出文件
    • 文件监听的方式有两种: - 启动webpack命令时,带上watch参数 - 在配置webapck.config.js是,设置watch:true
        modeule.export={
            //默认是false
            watch:true,
            watchOptions:{
                ignored:/node_modules,//默认为空,设置不监听的文件或文件夹
                aggregateTimeout:300,//监听到变化后会等300ms后再去执行,默认300ms
                poll:1000 //判断文件是否发生变化,系统每隔1000ms去访问一次
            }
        }
    

    webpack之tree sharking

    Tree Shaking 只支持ES MOdule形式,他可以把你 import 入但是没有使用的代码移除,就想摇树一样,把一些不需要的东西摇落在地上。

    • sideEffects
      • 在一个纯粹的 ESM 模块世界中,识别出哪些文件有副作用很简单。然而,我们的项目无法达到这种纯度,所以,此时有必要向 webpack 的 compiler 提供提示哪些代码是“纯粹部分”。比如我们再一个文件中 import style.css ,作用于这个文件的样式,但是并不会在代码的引用,但是tree sharking 是会认为这个是无用代码移除,此时我们便可以再 package.json中配置sideEffects 来避免样式移除。
      "sideEffects": [
          "*.css"
        ],
      

    webpack之代码分离

        /**
         *  代码分割,优化加载速度
         *  runtimeChunk:用于放置 业务代码和node-modules之间关联的代码,一个非常好的优化的点。
         *  chunks:async 表示只对异步代码生效 all对异步同步都生效
         *  minSize 大于这个值会做代码分割
         *  minChunks:打一个模块至少用多少次的时候才做代码分割
         *  maxAsyncRequests: 同时加载的模块数
         *  maxInitialRequests: 入口文件最多分割模块数
         *  automaticNameDelimiter: 打包后文件的名字连接符
         *  name:true   cacheGroups里的名字生效
         *  cacheGroups 分割出来的代码分割到哪里去,比如,jquery lodash等引入在node-modules  都打包到vendors.js
         *  priority值越大,优先级越高,cacheGroups和default用哪个决定于priority值
         *  reuseExistingChunk:如果一个模块已经被打包了,后续会忽略
         */
        optimization:{
        runtimeChunk:{
            name: 'runtime'
        },
        usedExports:true,
        splitChunks:{
            chunks: "all"
            minSize: 30000,
            minChunks: 1,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            automaticNameDelimiter: '~',
            name: true,
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10
                 },
             default: {
                    minChunks: 2,
                    priority: -20,
                     reuseExistingChunk: true
                }
             }
        }
    }
    

    webpack之缓存

    • 通过使用 output.filename 进行文件名替换,可以确保浏览器获取到修改后的文件.[hash] 替换可以用于在文件名中包含一个构建相关(build-specific)的 hash,但是更好的方式是使用 [chunkhash] 替换,在文件名中包含一个 chunk 相关(chunk-specific)的哈希,这样只要每次hash值没变的文件,浏览器就可以从缓存中去找,对一些第三方库非常友好。
    output:{
        filename:'[name].[contenthash].js',
        chunkFilename:'[name].[contenthash].chunk.js',
        path:path.resolve(__dirname,'../dist')
    }
    

    webpack之shimming

    • webpack 编译器(compiler)能够识别遵循 ES2015 模块语法、CommonJS 或 AMD 规范编写的模块。然而,一些第三方的库(library)可能会引用一些全局依赖(例如 jQuery 中的 $)。这些库也可能创建一些需要被导出的全局变量。这些“不符合规范的模块”就是 shimming 发挥作用的地方。
    plugins: [
       new webpack.ProvidePlugin({
       $ : 'jquery',
       _: 'lodash'
       })
     ]
    

    webpack之alias

    • 在webpack.config.js中,通过设置resolve属性可以配置查找“commonJS/AMD模块”的基路径,也可以设置搜索的模块后缀名,还可以设置别名alias。设置别名可以让后续引用的地方减少路径的复杂度。
    resolve: {
       alias: {
         "@": resolve("../src"), // 这样配置后 @ 可以指向 src 目录
       },
     },
    

    webpack之环境变量

    • env是环境变量,在package.json中配置不同的值
    // package.json
    // --env.production 表示在运行 build 命令时,将env.production设置为true
    "scripts": {
        "dev": "webpack-dev-server --inline --config ./build/webpack.common.js",
        "build": "webpack --env.production  --config  ./build/webpack.common.js"
      }
      
     // webpack.common.js 
     // 在webpack.common.js 中我们可以这么拿 env 来判断
    module.exports=(env)=>{
        if(env && env.production){
            return merge(commonConfig,prodConfig)
        }else{
            return merge(commonConfig,devConfig)
        }
    }
    

    webpack之单页面路由问题

    • 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html。通过传入以下启用
    historyApiFallback: true
    

    webpack性能优化之打包速度

    • 升级webpack或者升级node、npm、yarn
    • 减少loader的作用范围和使用
      rules:[
          { 
              test: /\.js$/,
              exclude: /node_modules/,  //这里就不会对node_modules里的东西进行es6转换
              loader: "babel-loader" 
          },
      
    • 合理的利用plugin,使用官方社区推荐的插件(比如代码压缩,开发环境就不需要这个插件)

    webpack性能优化之合理配置resolve

     resolve: {
      extensions: ['.js', '.vue'],//在import文件时可以省略写.js,.vue
      alias: {
        'vue$': 'vue/dist/vue.common.js',//起别名,可以文件引入时直接使用
        'src': path.resolve(__dirname, '../src'),
        'assets': path.resolve(__dirname, '../src/assets'),
        'components': path.resolve(__dirname, '../src/components'),
        'common': path.resolve(__dirname, '../src/common'),
        'img': path.resolve(__dirname, '../resource/img')
      }
    }