webpack学习记录

101 阅读7分钟

webpack学习记录

定义:webpack是一个静态资源打包工具

浏览器对新技术的支持不足,识别不了比较高级的语法,webpack会将浏览器解析不了的语法编译成浏览器认识的语法,从而在浏览器运行.

功能介绍

webpack本身的功能是有限的

  • 开发环境:只能编译js中的ES Module语法
  • 生产环境:能编译Js中的ES Module语法,还可以压缩JS代码

基本使用

下载webpack 依赖

npm i webpack webpack-cli  -D

使用webpack进行编译

npx webpack ./src/main.js --mode=development

--mode="development" 用于指定环境

编译完成之后会输出一个dist文件,使用编译好的文件就可以了

小结

webpack能够帮助我们把浏览器不认识的语法编译成为浏览器可以认识的语法

由于webpack本身功能较少,只能处理JS资源一旦遇到CSS等其他资源就会报错

基本配置

5大核心配置

  1. entry(入口)

    指示webpack从哪个文件开始打包

  2. output(输出)

    指示webpack打包完成的文件输出到哪里去,如何命名等

  3. loader(加载器)

    webpack本身只能处理js、json等资源,其他资源需要借助loader,webpack才能解析

  4. plugins(插件)

    扩展webpack的功能

  5. mode(模式)

    主要由两种模式:

    • 开发环境:development
    • 生成环境:production

准备webpack配置

在项目根路径准备 一个webpack.config.js 文件

在该文件中添加:

//基本配置
const path = require('path')
​
module.exports = {
  entry: './src/main.js', //入口文件
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },//出口文件
  module: {
    rules:[] //加载器
  },
  plugins:[], //插件
  mode:'development' //环境
}
​
​

开发模式

  1. 编译代码,使浏览器能识别运行
  2. 代码质量检查,树立代码规范

处理样式资源

下载 css-loader

npm install --save-dev css-loader

npm install --save-dev style-loader

在webpack.config.js中配置:

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
          //处理顺序 (从后往前)
        use: ["style-loader",  //将JS中CSS通过创建style标签添加到html文件中生效
              "css-loader"],   //将CSS资源编译成commonJS的模块到JS中
      },
    ],
  },
};

处理less/sass样式

下载less/sass-loader

npm i less/sass-loader

在webpack.config.js中配置:

module.exports = {
  module: {
    rules: [
      {
        test: /.less/$/,
        use: ["style-loader", "css-loader","less-loader"],
      },
    ],
  },
};
//sass样式将文中less改为sass

今日小结

  • 学习了如何使用webpack对项目进行打包
  • 学习了webpack的基本配置
  • 学会了如何使用loader进行处理样式资源

处理图片资源

添加type配置项:'asset' 即可无需下载loader

 {
        test: /.(png|jpe?g|gif|webp|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 小于10KB的图片会转base64
            // 优点:减少请求数量 缺点:体积会更大
            maxSize:10*1024 //10kb
          }
        }
      }

分类打包资源

module.exports = {
  entry: './src/main.js', //入口文件
  output: {
    // 所有文件的输出路径
    path: path.resolve(__dirname, 'dist'),
    // 入口文件打包输出名
    filename: 'static/js/main.js'
  },//出口文件
  module: {
    rules: [
      {
        test: /.(png|jpe?g|gif|webp|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 小于10KB的图片会转base64
            // 优点:减少请求数量 缺点:体积会更大
            maxSize:10*1024 //10kb
          }
        },
        generator: {
          //输出图片名称
          //hash:10:hash值取前十位
          filename:"static/images/[hash:10][ext][query]"
        }
      }
    ], //加载器
  },
}
      }

自动清空上次打包结果

output中配置clean:true

在webpack@4及之前中需要使用插件

module.exports = {
  entry: './src/main.js', //入口文件
  output: {
    // 所有文件的输出路径
    path: path.resolve(__dirname, 'dist'),
    // 入口文件打包输出名
    filename: 'static/js/main.js',
    //自动清空上次打包结果
    clean:true,
  },//出口文件
}

eslint的基础使用

在项目根目录添加.eslintrc.js文件

module.exports = {
  root: true,
  env: {
    node: true,     //启用node全局变量
      browser:true  //启用浏览器全局变量
  },
  'extends': [  //语法包
    'plugin:vue/essential',
    'eslint:recommended'
  ],
  parserOptions: {
    parser: '@babel/eslint-parser'
  },
  rules: { //规则  rules中的规则会替换掉语法包中的规则
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
     'vue/multi-word-component-names': 0
  }
}

Babel的基本使用

babel主要用于将ES6语法编写的代码转换为向后兼容的JavaScript语法,便于在旧版本的浏览器或其他环境中运行

下载babel插件及依赖npm install -D babel-loader @babel/core @babel/preset-env

基本配置

在项目根目录添加babel.config.js

module.exports = {
  presets: [ //预设
    '@vue/cli-plugin-babel/preset'
  ]
}
//在webpack中配置
module: {
  rules: [
    {
      test: /.m?js$/,
      exclude: /(node_modules|bower_components)/, //忽略文件
      loader: 'babel-loader',       
    }
  ]
}

处理html资源

下载npm install --save-dev html-webpack-plugin

能够自动引入js/CSS资源

const HtmlWebpackPlugin = require('html-webpack-plugin'); //引入插件
//使用插件
  plugins: [
    new HtmlWebpackPlugin({
        //需添加配置 否则页面没东西
        //新的html特点,结构和原来的一至,会自动引入打包资源
        template:path.resolve(__dirname,'public/index.html')
    })
  ], 

自动重新编译

修改目录下文件中的代码会自动重新编译打包

下载npm i webpack-dev-server -D

在Module.exports中添加配置:

//开发服务器 
devServer: {
    host: '127.0.0.1', //服务器地址
    port:3000,  //服务器端口
    open: true, //是否自动打开页面
  },
     //启动方式 npx webpack serve

开发环境配置总结

在项目根目录中添加webpack.config.js文件

//在module.exports中添加配置对象
module.exports={
    entry:'./src/main.js', //入口文件
    output:{ //出口配置
    // 所有文件的输出路径
    path: path.resolve(__dirname, 'dist'),
    // 入口文件打包输出名
    filename: 'static/js/main.js'
    },
    module:{  //loader配置
      rules: [
       {  //处理样式loader
        test: /.css$/,
        use: ["style-loader", "css-loader"],
       },
       {  //处理图片loader 小于10KB的转为base64编码 并更改其输出路径
        test: /.(png|jpe?g|gif|webp|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 小于10KB的图片会转base64
            // 优点:减少请求数量 缺点:体积会更大
            maxSize:10*1024 //10kb
          }
        },
        generator: {
          //输出图片名称
          filename:"static/images/[hash:10][ext][query]"
        }
       },
      { //其他资源的处理
        test: /.(ttf|woff2?|mp3|mp4|avi)$/,
        type: 'asset/resource',
        generator: {
          // 输出名称
          filename:'static/media/[hash:10][ext][query]'
        }
      },
      ]
    },
    plugins: [ //插件配置
        new HtmlWebpackPlugin({
          template:path.resolve(__dirname,'public/index.html')
       })
    ], 
    devServer: {  //开发服务器
      host: '127.0.0.1',
      open: true,
      port:3000,
    },
    mode: 'development' //环境配置
}

生产环境

生产环境是代码开发完毕,需要上线的代码

主要对代码进行优化,让其运行性能更好

优化主要从两个角度出发

  1. 优化代码运行性能
  2. 优化代码打包速度

准备两个配置文件用于开发和生产环境

新建一个config文件夹

添加webpack.dev/prod.js 文件

dev下存开发环境的配置

prod存生产环境的配置

在package.json中

配置启动项目命令

 "scripts": {
    "serve": "npm run dev",
    "dev" : "npx webpack serve --config ./config/webpack.dev",
    "build": " npx webpack --config ./config/webpack.prod"
  },

CSS处理

提取CSS成单独文件

CSS文件目前被打包到js文件中,当js文件加载时,会创建一个style标签来生成样式

这样会出现闪屏现象

通过单独的CSS文件通过link标签加载性能较好

下载npm i mini-css-extract-plugin -D

在配置文件中使用:

const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //引入插件module.exports = {
  plugins: [new MiniCssExtractPlugin({
      fliename:'static/css/main.css'
  })],
  module: {
    rules: [
      {
        test: /.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
};

css的压缩

下载npm install css-minimizer-webpack-plugin --save-dev

在配置中添加

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //引入插件
module.exports = {
  plugins: [ new CssMinimizerPlugin()]
}

webpack基础篇总结

学会了webpack的基本使用方法

  1. 掌握了两种开发模式
  • 开发模式:代码能编译自动化运行
  • 生产模式:代码编译优化输出
  1. 掌握了webpack的基本功能
  • 开发模式:可以编译ESModule语法
  • 生成模式:可以编译ES Module语法,压缩JS代码
  1. 掌握了webpack基本配置文件
  • 5个核心概念

    • entry
    • output
    • loader
    • plugins
    • mode
  • devServer配置

  1. webpack脚本指令用法
  • webpack直接打包输出
  • webpack serve启动开发服务器,内存编译打包没有输出

今日小结

  • 学会了处理图片资源

  • 资源分类打包

  • eslint/babel的基本使用

  • 添加html自动引入打包资源

  • 添加开发服务器 自动重新编译

  • 提取CSS成单独文件及CSS的代码压缩

高级优化篇

从四个方面对项目进行优化,让代码在运行时性能更好

  1. 提升开发体验
  2. 提升打包构建速度
  3. 减少代码体积
  4. 优化代码运行性能

提升开发体验

问题: 在开发过程中编写代码容易出现各种各样的小问题,开发者调试工具能够帮我们找到问题,但是经过编译的代码的报错内容是编译之后的,与源文件有差异,我们想快速定位错误可以使用SourceMap

解决方案: SourceMap(源代码映射)是用来生成源代码与构件后代码一一映射的文件的方案

它会生成一个xxx.map文件,里面包含源代码和构建后代码每一行每一列的映射关系,当构件出错了会通过xxx.map文件从构建后代码出错位置找到映射后代码出错位置,从而让浏览器提示源代码文件出错位置,让我们更快找到错误根源

使用:

SourceMap的值有很多种情况

实际开发中只需要关注两种情况

  • 开发模式:cheap-module-source-map

    • 优点:打包编译速度快,只包含行映射
    • 缺点:没有列映射
  • 生成模式:source-map

    • 优点:包含行/列映射
    • 缺点:打包编译速度慢
module.exports = { 
    mode: 'development', //环境
    devtool:'cheap-module-source-map'
}

提升打包构建速度

模块热替换(hot module replacement)

问题: 开发时我们修改了一个模块代码,webpack会将所有模块全部重新打包,速度很慢,所有我们需要修改某个模块,只重新编译这个模块,其他模块不变,这样打包速度就会更快

解决方案: 模块热替换(hot module replacement)

开启这个选项就会只编译修改的模块

devServer{  
    hot:true, //模块热替换
    host:'127.0.0.1',
    port:'3000',
    open:true
}

oneOf

问题: 打包是每个文件都会经过所有loader处理,虽然因为test正则原因没有实际上处理,但是都要过一遍比较慢

解决: 使用oneOf 只会匹配上一个loader,剩下的不匹配

使用:

module.exports = {
    module:{
        rules:[
            {
                oneOf:[
                    {
                        test:/.css$/,
                         use: ["style-loader", "css-loader"],
                    }
                ]
            }
        ]
    }
       
}

Include/Exclude

问题: 开发时我们需要使用第三方库或插件,所有文件都下载到node_modules中了这些文件是不需要编译可以直接使用的

解决:* *

  • Include 包含:只处理xxx文件
  • Exclude 排除:除了xxx文件以外都处理

使用:

module.exports = {
    module:{
        rules:[
               {
                 test: /.m?js$/,
                 exclude: /(node_modules|bower_components)/,  //排除node_modules
                 loader: 'babel-loader',
               }
        ]
    }
       
}

Cache

问题: 每次打包时JS文件都要经过Eslint检查和babel编译,速度较慢,我们可以缓存之前的Eslint检查和babel编译结果,这样第二次打包时速度就会更快了

解决: 使用Cache对Eslint检查和Babel编译结果进行缓存

使用:

module.exports = {
    module:{
        rules:[
               {
                 test: /.m?js$/,
                 exclude: /(node_modules|bower_components)/,  //排除node_modules
                 loader: 'babel-loader',
                 options:{
                     cacheDirectory:true,//开启Babel缓存
                     cacheCompression:false,//关闭缓存文件压缩
                 }
               }
        ]
    }
       
}

多进程打包

Thead

问题: 我们想要继续提升打包速度,其实就是想要提升JS的打包速度,因为其他文件都比较少,而对JS文件处理主要就是Eslint、Babel、Terser三个工具,所以我们要提升它们的运行速度,我们可以开启多进程同时处理JS文件

解决: 多进程打包:开启电脑的多个进程同时干一件事,速度更快

使用:

下载npm i thread-loader -D

const os = require('os')  //引入node内置os 模块
const threads = os.cpus().length  //获取CPU的核数
const TerserPlugin =require('terser-webpack-plugin') 引入插件
module.export={
    module:{
        rules[
           {
             test: /.m?js$/,
             exclude: /(node_modules|bower_components)/,
             use: [
                {
                  loader: "thread-loader",//开启多线程打包
                  options: {
                    works: threads  //进程数量
                  }
                },
                {
                  loader: "babel-loader",
                  options: {
                    cacheDirectory: true,//开启Babel缓存
                    cacheCompression: false,//关闭缓存文件压缩
                  }
                }
             ],
           }
        ]
    },
 optimization: {
    minimize: true,
    minimizer: [
      // 压缩JS
      new TerserPlugin({
        parallel: threads,  //启用多进程并发运行并设置并发运行次数。
      }),
    ],
  },
}

减少代码体积

Tree Shaking

问题: 开发中我们会定义一些工具函数库,或者引用第三方工具函数库或者组件库

如果没有特殊处理,在打包时会引入整个库,但实际中可能只用一小部分的功能,将整个库打包进来,体积太大

解决: Tree Shaking会移除JS中未使用的代码

使用: webpack已经默认开启了这个功能,无需额外配置

Babel

问题: Babel为编译的每个文件都插入了一些辅助代码,使代码体积过大。

Babel对一些公共方法使用了非常小的辅助代码,如:_extend,默认情况下会被添加到每一个需要它的文件中

解决: @babel/plugin-transform-runtime:禁用了Babel自动对每个文件的runtime注入,而是引入@babel/plugin-transform-runtime并且使所有辅助代码从这里引用 使用: 下载npm i @babel/plugin-transform-runtime -D

  {
    loader: "babel-loader",
    options: {
      cacheDirectory: true,//开启Babel缓存
      cacheCompression: false,//关闭缓存文件压缩
      plugins: ['@babel/plugin-transform-runtime']
     }
   } 

今日小结

  • 学会了如何提升开发体验

    • 使用SourceMap生成映射map文件,快速定位至问题点
  • 提高打包构建速度

    • 使用模块热替换,让其只编译修改的模块
    • 使用oneOf,让其只匹配上一个loader,剩下的跳过,提升构建速度
    • 使用include/exclude:只编译xx部分/过滤node_modules
    • 使用Cache对Babel编译结果和Eslint检查进行缓存
    • 开启多进程打包,多进程并发运行
  • 减少代码体积

    • webpack内置的Tree Shaking自动移除JS中未使用的代码
    • 禁用Babel自动对每个文件的runtime注入,使用@babel/plugin-transform-runtime对辅助代码的引用