webpack5系统学习


const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
//浏览器兼容性问题默认设置的是生产环境
// 若要设置为开发环境,此处添加 process.env.NODE_ENV = 'development'

//压缩css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

/*
  PWA:渐进式网络开发应用程序(离线可访问)
  workbox --> workbox-webpack-plugin
*/
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')

/*
  tree shaking : 去除无用代码
    前提:1.必须使用ES6模块化  2.开启production环境 
    作用:减少代码体积

    在package.json中配置
      "sideEffects": false 所有代码都没有副作用 (都可以进行 tree shaking)
      问题: 可能会把 css / @babel/polyfill (副作用)文件干掉
      "sideEffects": ["*.css","*.less"] 使不会对css文件处理
 */

/*
  缓存:
    babel缓存
      cacheDirectory:true
      -->让第二次打包构建速度更快
    文件资源缓存
      hash:每次webpack构建时会生成一个唯一的hash值。
        问题:因为js和css同时使用一个hash值。
          如果重新打包,会导致所有缓存失效(可能我值改动一个文件)
      chunkhash(代码块hash,以同一个入口文件):根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值旧一样
        问题:js和css的hash值还是一样的
          因为css是在js中被引入的,所以同属于一个chunk
      contenthash:根据文件内容生成hash值,不同文件hash值一定不一样
      -->让代码上线运行缓存更好使用
*/


//正常来说一个文件那只能被一个loader处理,如果需要被多个loader处理,需要指定loader的执行顺序
// 先执行eslint 再执行babel ebforce:'pre'
module.exports = {
  entry: {
    // 多入口
    index: './src/js/index.js',
    test: './src/js/test.js'
  },
  output: {
    // [name]:取文件名
    filename: 'js/[name].[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  // 单入口
  // entry: './src/index.js',
  // output: {
  //   filename: 'built.[contenthash:10].js',
  //   path: resolve(__dirname, 'build')
  // },
  module: {
    rules: [
      // oneOf提升构建速度,使一个文件不会被所有loader匹配
      {
        // 以下loader只会匹配一个
        oneOf: [
          {
          // ...
          }
        ]
      },



      {
        // 语法检查 eslint-loader eslint
        // 值检查自己写的代码,第三方库不用检查的
        // 设置检查规则 在package.json中eslintConfig中设置
        //"eslintConfig": {
        //   "extends": "airbnb-base"
        // }
        // 使用airbnb规则需要下载 --> eslint-config-airbnb-base eslint-plugin-import eslint
        test: /\.js$/,
        exclude: /node_modules/,
        // 设置优先执行
        enforce:'pre',
        loader: 'eslint-loader',
        options: {
          // 自动修复错误
          fix:true
        }
      },

      // js兼容性处理 babel-loader @babel/preset-env @babel/core
      // @babel/preset-env 问题是只能转换基本语法,promise等语法无法转换
      // @babel/polyfill 可以兼容全部js 问题是体积太大 只需要在index.js中引入即可 import '@babel/polyfill'
      // core-js按需加载
      {
        test: /\.js$/,
        exclude:/node_modules/,
        loader: 'babel-loader',
        options: {
          // 预设:还是babel做怎样的兼容性处理
          // presets:['@babel/preset-env'],
          presets:[
            [
              '@babel/preset-env',
              //按需加载
              {
                useBuiltIns: 'usage',
                // 指定corejs版本
                corejs: {
                  version:3
                },
                // 兼容性做到那个版本浏览器
                targets: {
                  chrome: '60',
                  firefix: '60',
                  ie: '9',
                  safari: '10'
                }
              }
            ]
          ],
          // 开启babel缓存
          // 第二次构建时,会读取之前的缓存
          cacheDirectory: true
        }
      },

      /*
        开启多进程打包 thread-loader
        进程启动大概为600ms,进程通信也有开销
        只有工作消耗时间比较长,才需要进行多进程打包
      */
      {
        test: /\.js$/,
        exclude:/node_modules/,
        use:[
          // 'thread-loader', //默认按照cpn核数-1
          {
            loader: 'thread-loader',
            options: {
              workers: 2 //进行2个
            }
          },
          {
            loader: 'babel-loader',
            options: {
              // 预设:还是babel做怎样的兼容性处理
              // presets:['@babel/preset-env'],
              presets:[
                [
                  '@babel/preset-env',
                  //按需加载
                  {
                    useBuiltIns: 'usage',
                    // 指定corejs版本
                    corejs: {
                      version:3
                    },
                    // 兼容性做到那个版本浏览器
                    targets: {
                      chrome: '60',
                      firefix: '60',
                      ie: '9',
                      safari: '10'
                    }
                  }
                ]
              ],
              // 开启babel缓存
              // 第二次构建时,会读取之前的缓存
              cacheDirectory: true
            }
          }
        ]
      },

      {
        test: /\.css$/,
        use: [
          //创建style标签,将样式引入
          // 'style-loader',

          //取代style-loader 作用提取js中的css成单独文件
          MiniCssExtractPlugin.loader,

          //将css文件整合到js文件
          'css-loader',

          // css兼容性处理 postcss --> postcss-loader postcss-preset-env
          //帮postcss找到package.json 中browserslist里面的配置,通过配置加载指定的css兼容性样式
          //"browserlist": {
          //"development": [
          //   "last 1 chrome version",
          //   "last 1 firefox version",
          //   "last 1 safari version"
          // ],
          // "production": [
          //   ">0.2%",
          //   "not dead",
          //   "not op_mini all"
          // ]
          //}

          //postcss-loader
          // 修改loader的配置
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => {
                require('postcss-preset-env')
              }
            }
          }
        ]
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 问题,处理不了html中img图片
        test: /\.(jpg|png|gif)$/,
        //url-loader file-loader
        loader: 'url-loader',
        options: {
          //图片大小小于8kb 就会被base64处理
          //优点:减少请求数量(减轻服务器压力)
          //缺点:图片体积会更大(文件请求速度更慢)
          limit: 8 * 1024,
          //问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
          //解析时会出现问题:[objext Module]
          //解决:关闭url-loader的es6模块化,使用commonjs解析
          esModule:false,
          //给图片进行重命名
          //[hash:10]取hash的前10位  [ext]取文件原来的扩展名
          name: '[hash:10].[ext]'
        }
      },
      {
        test: /\.html$/,
        //用于处理html文件中的img图片(负责引入img,从而能被url-loader进行处理)
        loader: 'html-loader'
      },
      {
        // 打包出html/js/css以外的其他资源
        exclude: /\.(css|js|html|less|jpg|png|gif)$/,
        loader:'file-loader',
        options: {
          name: '[hash:10].[ext]',
          // 输出目录build/imgs
          outputPath: 'imgs'
        },
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      // 压缩html
      minify: {
        // 移除空格
        collapseWhitespace: true,
        // 移除注释
        removeComments: true
      }
    }),


    new MiniCssExtractPlugin({
      // 对生成的文件重命名
      filename: 'css/built.css'
    }),


    // 压缩css
    new OptimizeCssAssetsWebpackPlugin(),


    // pwa 在入口文件中需配置
    /*
      注册serviceworker
      处理兼容性问题
      if('serviceWorker' in navigator) {
        windwo.addEventListener('load', () => {
          navigator.serviceWorker
          .register('/service-worker.js')
          .then(()=>{
            console.log('注册成功')
          })
          .catch(()=>{
            console.log('注册失败')
          })
        })
      }
      1.由于识别不了window navigator等,会报eslint错误
      解决:需修改package.json中eslintConfig配置
      "env": {
        "broser": true
      }
      2.sw代码必须运行在服务器上
      -->1种是nodejs
      -->另一种是 npm i serve -g
      serve -s build 启动服务器 将build 目录下所有资源作为静态资源暴露出去

    */
    new WorkboxWebpackPlugin.GenerateSW({
      /*
       1.帮助serviceworker快读启动
       2.删除旧的serviceworker

       生成一个 serviceworker 配置文件
       */
      clientsClaim: true,
      skipWaiting: true
    })
  ],

  /* 
    code split 分割代码
    可以将node_modules中代码单独打包成一个chunk最终输出
    自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
  */
  optimization:{
    splitChunks: {
      chinks: 'all'
    }
  },

  mode: 'development',

  // 有些包需要用script标签通过cnd引入,需要忽略库
  extermals: {
    // 拒绝jQuery
    jquery: 'jQuery'
  },

  //开发服务器 devServer: 用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
  //特点:只会在内存中编译打包,不会有任何输出
  //启动devServer指令为 npx webpack-dev-server
  devServer: {
    //项目构建后的路径
    contentBase: resolve(__dirname, 'build'),
    //启动gzip压缩
    compress: true,
    //端口号,
    port: 3000,
    //自动打开浏览器
    open: true,
    //开启HMR功能 只更新修改部分 便于更改某一个模块时,页面不全部刷新,只更新指定模块
    // 样式文件 style-loader内部实现了HMR
    // html文件默认不能使用HMR  一旦开启HMR功能,将无法热更新,此时在entry中添加html路径,即可热更新
    // js文件默认不能使用hmr功能 --》需要在入口文件修改js代码,添加支持HMR功能的代码
    // 入口文件添加代码块  改变print.js代码 只更新此模块
    // if(module.hot){
    //   module.hot.accept('.print.js',function(){
    //     操作
    //   })
    // }
    hot: true,
  },
  devtool: 'eval-source-map'
  // 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-mao
  //        cheap-source-map

  // vue中使用的是  eval-source-map  /eval-cheap-module-source-map

  // 生产环境:需确认源代码要不要隐藏?调试要不要更友好
  // 内联会让代码体积变大,所以生产环境不用内联
  // nosources-source-map 全部隐藏
  // hidden-source-map 只会隐藏源代码,会提示构建后代码错误信息

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

// 懒加载和预加载
document.getElementById('btn').onclick = function() {
  // 懒加载:当文件需要使用时才加载
  // 预加载 prefetch: 会在使用之前,提前加载js文件
  // 正常加载可以认为时并行加载(同一时间加载多个文件)
  // 预加载 prefetch: 等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
  import (/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({mul})=>{
    console.oog(mul(4.5))
  })
}


/*
dll与external的区别
dll只打包一次,下一次速度就快了
external是完全不打包 只通过cdn引入

创建文件webpack.dll.js文件
  使用dll技术,对某些库(第三方库:jquery,vue...)进行单独打包
  当你运行 webpack 时,默认查找 webpack.config.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: [
    // 打包生成一个 mainfest.json --> 提供和jquery映射
    new webpack.DllPlugin({
      name: '[name]_[hash]',//映射库的暴露的内容名称
      path: resolve(__dirname, 'dll/mainfest.json')//输出文件路径
    }),
  ],
  mode: 'production'
}
/*
在webpack.config.js中
  const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
    // 告诉webpack哪些库不参与打包,同时使用时的名称也得变
    new webpack.DllReferencePlugin({
      mainfest:resolve(__dirname, 'dll/mainfest.json')
    }),
    // 将某个文件打包输出去,并在html种自动引入该资源
    new AddAssetHtmlWebpackPlugin({
      filePath: resolve(__dirname,'dll/jquery.js')
    })
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值