尚硅谷webpack课程学习笔记

为什么需要使用打包工具?

开发时使用的框架、es6 语法 、less 等浏览器无法识别。
需要经过编译成浏览器能识别的css、js才可以运行。
打包工具可以帮我们编译,还可以做代码压缩、兼容处理、性能优化。

常见的打包工具有什么?
vite、webpack、glup、grunt

webapck最基本的使用?
是一个静态资源打包工具,以一个或多个文件为打包入口,将项目中所有文件编译组合成输入一个或多个文件。这个输出的文件我们叫budle,他就是经过编译可以在浏览器运行的文件。

webpack本身的功能是有限的?
开发模式:仅仅编译js modle语法
生产模式:编译js modle语法、压缩js代码

package.json 是什么文件?
通常我们需要安装一些依赖包,而在下载这个包之前,我们需要包描述文件。通常描述这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证、如何启动项目、运行脚本等元数据。
package.json 一般在项目创建之初创建。创建方式可以手动(直接在项目根目录新建一个 package.json 文件)、也可以npm init -y 初始化一个,y 就是要使用配置的默认值
package.json文件就是一个JSON对象,该对象的每一个成员就是当前项目的一项设置

webpack 安装文档,不建议全局安装
练习步骤:
1、新建一个包,名称不能和webpack重复
2、创建基本的mani.js 文件、src、public文件、写入es6 模块化语法,报错,浏览器无法识别。
3、试试使用webpack 后能否识别呢?无法解析modle语法
4、引入之前需要初始化一个包描述文件 npm init -y
5、npm install webpack webpack-cli --save-dev
6、安装成功后执行npx webpack ./src/main.js --mode=development ,npx 会将node—module 的bin 下面的内容临时添加到环境变量。
7、执行上面即可打包了。默认输出到dist,可以观察输出文件,是编译后的文件。
8、npx webpack ./src/main.js --mode=production 生产模式,会压缩代码

webapck的五大核心概念
入口entry
输入output
loader webpack本身只能处理js、json等资源,其他资源需要借助loader
plugin 拓展功能
mode 模式:生产、开发

练习步骤:
1、安装好之后建一个webpack的配置文件,在根路径下,并且文件名必须是webpack.config.js
2、添加基本配置
3、我们之前打包执行的是npx webpack ./src/main.js --mode=development 这个命令,写了webpack的配置文件中设置了入口后,可以直接使用npx webpack 执行了。上面是使用cli的方式运行本地的webpack,但这样还是有些麻烦。
4、在 package.json 文件中添加一个 npm script: “build”: “webpack”
现在,可以使用 npm run build 命令替代之前使用的 npx 命令。注意,使用 npm scripts 便可以像使用 npx 那样通过模块名引用本地安装的 npm packages。
拓展,可以学习下npm中文文档

资源管理
1、使用style样式,需要借助loader
2、npm install --save-dev style-loader css-loader
3、添加配置,参考官网

1、使用less资源
2、npm install less less-loader --save-dev
3、添加配置,参考官网

1、图片资源的使用
2、不需要要下载,使用内置的asset即可。资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。``关于这块配置webpack官网介绍
3、添加配置,

{
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
},

1、对文件的加载,如 JSON 文件、CSV、TSV 和 XML。
2、npm install --save-dev csv-loader xml-loader
3、添加配置,参考官网

调整文件打包输出目录
每一次打包都会在dist下多一些文件,而且很混乱。我们在下一次打包之前手动删除dist,再重新打包。
并设置输出路径,文件资源可设置输出路径。
为特定资源指定输出路径

   generator: {
          filename: 'asset/[hash:10][ext][query]'
   }

可不可以不每次都需要手动删除呢?
能不能自动清除dist文件上次内容?可以,在output 对象中配置clean:true 即可。

处理js资源
webpack对于js资源的处理是有限的,只能处理model语法,对于es6新语法不兼容,我们需要使用babel
在转换之前先介绍一下eslint ,用于检查js和jsx语法的工具。更多介绍eslint官网

在webpack中使用eslint
1、npm install eslint-webpack-plugin --save-dev
2、npm install eslint --save-dev
3、添加配置,参考官网

const ESLintPlugin = require('eslint-webpack-plugin');

module.exports = {
  // ...
  plugins: [new ESLintPlugin({
      context:path.resolve(__dirname,'src'),
    })]
  // ...
};

4、运行起来报错,缺少eslint的配置文件。我们在根目录下新建 .eslintrc.js 文件名不能改。
然后具体的配置可以参考官网,可以继承推荐的默认配置。

5、发现dist下定义的文件也被eslint 检查了,但我们并不需要检查这些文件。在根目录下创建一个 .eslintignore 文件,写上需要忽略的文件路径即可。

在webpack中使用babel

关于bable的介绍可以看bable官网
1、npm install -D babel-loader @babel/core @babel/preset-env webpack
2、配置,参考官网 bable配置
3、配置可以直接写在webpack的配置文件中,也可以在根目录创建 babel.config.js 配置。

处理html资源
1、原本html中引入的js资源是这么写的

 <script src="../dist/main.js"></script>

引入的是打包编译后的文件,如果更改入口起点的名称,或者添加一个新的入口,那么会在构建时重新命名生成的 bundle,但是 index.html 仍然在引用旧的名称!而且如果需要引入很多资源,手动维护非常困难。
我们可以使用 HtmlWebpackPlugin (为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中)来解决这个问题。
安装:

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

配置:

  new HtmlWebpackPlugin({
      title: '管理输出',
      // 模板:以public/index.html 文件创建新的html 这样打包之后的html不会把之前的东西丢掉
      template:path.resolve(__dirname,'public/index.html')
    }),

使用了这个插件,我们无需在html中手动引入,他会自动帮我们引入并且在输出文件中新增一个html文件。

搭建开发服务器
我们之前每次改动了src的内容,都需要编译之后才能看到效果,需要手动执行npx webapck ,我们希望webpack能自动化,可以使用
webpack-dev-server,他相当于webpack 启动了一个服务器,他会帮我们监听src下所有的改动,只有有改动会帮我们自动打包编译。
安装

npm install --save-dev webpack-dev-server

配置

devServer:{
    host:'localhost',// 启动服务器的域名
    port:'8080',// 启动服务器端口号,
    open:true,// 是否自动打开浏览器
    static: './dist', // 将 dist 目录下的文件 serve 哒服务器
  },

执行命令

npx webpack serve 

添加一个可以直接运行 dev server 的 script:

 "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
     "watch": "webpack --watch",
     "start": "webpack serve --open",
     "build": "webpack"
   },

在命令行中运行 npm start,会看到浏览器自动加载页面。

eee,报错了!

报错内容:

Error: Cannot find module ‘ajv/dist/compile/codegen’

解决办法:

npm i ajv
npm install ajv-errors@1.0.1

再次启动
eee,又报错了!

报错内容:

Error: Conflict: Multiple chunks emit assets to the same filename static/js/bundle.js (chunks main and vendors-node_modules_react-hot-loader_patch_js-node_modules_react_jsx-dev-runtime_js-node_mod-4610d2)

解决办法:

让它工作不得不改变filename: "static/js/bundle.js"至filename: "static/js/[name].js"

output: {
    path: undefined,
    publicPath: "/",
    filename: "static/js/[name].js",
    chunkFilename: "static/js/[name].chunk.js",
}

再次启动可以了

在这里插入图片描述

webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样。如果你的页面希望在其他不同路径中找到 bundle 文件,可以通过 dev server 配置中的 devMiddleware.publicPath 选项进行修改。

意思就是开发模式下不会生成打包后的文件,尝试把dist删除,保存后自动打包确实没有生成dist文件了
修改js文件内容页面自动更新了。

生产和开发环境两套配置
development(开发环境) 和 production(生产环境) 这两个环境下的构建目标存在着巨大差异。在开发环境中,我们需要:强大的 source map 和一个有着 live reloading(实时重新加载) 或 hot module replacement(热模块替换) 能力的 localhost server。而生产环境目标则转移至其他方面,关注点在于压缩 bundle、更轻量的 source map、资源优化等,通过这些优化方式改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。

首先我们新建一个config文件夹,分别新建webpack.dev.js 和 webpack.prod.js 两个文件
将文件中使用相对路径的地方加个…/

 template:path.resolve(__dirname,'../public/index.html')

但是入口文件路径不改变,因为配置文件运行时在根目录

  entry:'./src/main.js',

生产环境不需要dev-server

分别添加两个命令

  "build": "webpack --config ./config/webpack.prod.js",
  "start": "webpack serve --config ./config/webpack.dev.js"

执行对应的命令,生产环境下的budle 有压缩。

虽然,以上我们将 生产环境 和 开发环境 做了细微区分,但是,请注意,我们还是会遵循不重复原则(Don’t repeat yourself - DRY),保留一个 “common(通用)” 配置。为了将这些配置合并在一起,我们将使用一个名为 webpack-merge 的工具。此工具会引用 “common” 配置,因此我们不必再在环境特定(environment-specific)的配置中编写重复代码。

我们先从安装 webpack-merge 开始,并将之前指南中已经成型的那些代码进行分离:

npm install --save-dev webpack-merge

新建一个webpack.common.js文件,写入公共配置
在生产和开发文件中分别引入即可。

 const { merge } = require('webpack-merge');
 const common = require('./webpack.common.js');

 module.exports = merge(common, {
   mode: 'production',
 });

提取css成单独文件
我们可以看到,现在我们的css文件,是被打包到了js中,当js文件加载时,会创建一个style 标签来生成样式。
只有js加载完了,页面才会出现样式,给用户闪屏的感觉,体验不好。
应该是将样式抽离到单独的css文件中,通过link标签引入,加载的性能才好
借助插件MiniCssExtractPlugin来实现,官网介绍
在这里插入图片描述
1、安装:

npm install --save-dev mini-css-extract-plugin

2、配置

官方建议 mini-css-extract-plugin 与 css-loader 一起使用。
将styel-loader 替换为MiniCssExtractPlugin.loader,因为插件会将 CSS 提取到单独的文件中,
为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
不再需要创建style 标签了

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
use: [MiniCssExtractPlugin.loader, 'css-loader'],


现在已经被打包到main.css 中了
在这里插入图片描述

css 兼容性处理
postcss-loader 官网介绍
可以帮我们处理一些样式兼容性问题
1、安装

npm install --save-dev postcss-loader postcss postcss-preset-env 

2、配置,必须写在css-loder 后面

{
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  [
                    'postcss-preset-env',
                    {
                      // 其他选项
                    },
                  ],
                ],
              },
            },

3、在package.json 中添加配置
设置浏览器兼容需要做到什么程度。
最近一个版本,99%任然再使用的浏览器

  "browserslist" :[
    "last 2 version",
    "< 1%",
    "not dead"
  ]

css压缩处理
通过观察可以发现,我们dist目录下的资源,js和html都压缩了。但css文件没有压缩处理。
我们可以借助CssMinimizerWebpackPlugin 插件,官网介绍
在这里插入图片描述

1、安装

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

2、配置

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
  optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin(),
    ],
  },

再次打包已经被压缩了
在这里插入图片描述

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

sourceMap
开发时我们运行的代码是编译之后的,如果有报错,只能定位到编译后的位置,不便于我们排查问题。
sourceMap(源代码映射) 是一个用来生成源代码和映射代码构建的方案

他会生成xx.map 文件,里面包含源代码码和构建好的代码每一行,每一列的关系。从而让浏览器提示源文件的出错位置,从而帮我们快速定位错误。
如何使用devtool?官网介绍
具体配置:

开发模式:
  mode:'development',
  devtool:'cheap-module-source-map',

生成模式:
  mode:'production',
  devtool:'source-map',

经过测试,已经定位到具体一行了

HotModlueReplcaement
当我们在开发时只修改了某一个模块的代码,webpack在打包时会重新打包,速度很慢,页面整体重新刷新了。我们希望它只编译需要打包的模块,其他模块不变。

HotModlueReplcaement(热模块替换)在程序运行中,替换、添加、删除模块,而无需加载整页面,
如何使用?
从 webpack-dev-server v4.0.0 开始,热模块替换是默认开启的。

  devServer:{
    host:'localhost',// 启动服务器的域名
    port:'8080',// 启动服务器端口号,
    open:true,// 是否自动打开浏览器
    static: './dist',
    hot:true // 只应用与开发环境,生产环境不需要,默认开启
  },

但是只有css/html 可以做到,对于js 需要在入口文件manjs中

if(module.hot) {
  // 判断是否支持热模块替换功能,有的话需要一个个js文件添加
   module.hot.accept('./js/sum.js')
}

每个js文件都需要手动引入,太麻烦?
当然了,vue-loader,react-hot-loder 已经帮我们做了这些事情。

oneOf
打包时每个文件都会经过所有 loader 处理,例如一个css文件也会进过js文件的判断,虽然因为 test 正则原因实际没有处理上,但是都要过一遍比较慢。所以使用OneOf,匹配上一个 loader, 剩下的就不匹配了,开发模式和生产模式都可以用

 module: {//loader规则
    rules: [
     // 比如是css文件,匹配到之后处理use对应的一组loader,后续不再匹配
      {
        //每个文件只能被其中一个loader配置处理
        oneOf: [
          {
            test: /\.css$/i, // 用来匹配 .css 结尾的文件
            use: [
              "style-loader", //将js中css通过创建style标签添加到html中
              "css-loader" //该模块将css资源编译成commonjs的模块到js中
            ],//use 数组里面 Loader 执行顺序是从右到左(从下到上)
          },
          {
            test: /\.less$/i, // 用来匹配 .less 结尾的文件
            //loader:"xxx"只能使用1个loader
            use: [//use可以使用多个loader
              // compiles Less to CSS
              'style-loader',
              'css-loader',
              'less-loader',//将less变成css文件
            ],
          },

eslint 和babel 缓存
每次打包的时候js文件都需要经过eslint检查和babel编译,速度很慢。
我们如果能缓存之前的结果,第二次打包的速度就会快很多
对babel的配置

{
        test:/\.js$/,
        include:path.resolve(__dirname,'../src'),
        loader:'babel-loader',
        options:{
          cacheDirectory:true, // 开启babel缓存
          cacheCompression:false // 关闭缓存文件压缩
        }
      }

对eslin的配置

    new ESLintPlugin({
      context:path.resolve(__dirname,'../src'),
      exclude:"node_modules",
      // cache:true,// 开启缓存
      // cacheLocation:path.resolve(__dirname,'../node_modules/.cache/eslintcache')
    }),

多进程打包
我们打包的速度大部分时候是处理js文件的速度,而处理js文件主要就是eslint、bable、terser这三个工具,我们要提升他们的运行速度,可以开启多线程同时处理。
但是需要注意的是,仅在特别耗时的项目中使用,因为每个进程启动大约有600ms的开销
我们启动进程的数量就是cpu的核数。
如何获取自己电脑cpu的核数?

const os = require('os');
const threads = os.cpus().length;

还需要借助

npm i thread-loader -D

配置

 {
        test:/\.js$/,
        include:path.resolve(__dirname,'../src'),
        use:[
          {
           loader:'thread-loader',// 开启多进程
           options :{
            works:threads // 进程数量
           }

          },
          {
            loader:'babel-loader',
            options:{
              cacheDirectory:true, // 开启babel缓存
              cacheCompression:false // 关闭缓存文件压缩
            }
          }
        ],
       
   
      }

还需要引入一个插件

 optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin(),
      new TerserWebpackPlugin({
        parallel:threads
      })
    ],
  },

什么是tree-shaking

我们定义或引入了一些第三方工具函数或组件库,如果没做特殊处理的话,打包的时候会引入整个库,即使我们使用的是很小一部分功能。
依赖es model ,移除没有被引用的代码
webpack 默认开启了这个功能,无需配置

减少babel的体积
babel 会为每个编译后的文件添加辅助代码
Babel 对一些公共方法使用了非常小的辅助代码,比如 extend 。默认情况下会被添加到每一个需要它的文件中。
你可以将这些辅助代码作为一个独立模块,来避免重复引入。

babel/plugin-transform-runtime是什么
禁用了 Babel 自动对每个文件的 runtime 注入,而是引入babel/plugin-transform-runtime并且使所有辅助代码从这里引用babel/plugin-transform-runtime

1、安装

npm i @babel/plugin-transform-runtime -D

2、配置

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

图片压缩
插件官网介绍,使用方式直接参考官网,这里不记录了

代码分割,优化代码运行性能
我们打包时会将所有的js文件都打包到一个文件中,体积太大。如果我们只渲染首页,那么应该只加载首页的js文件,其他文件不需要加载。

所以我们就需要将打包生成的文件进行代码分割,生成多个js文件,渲染哪个页面就只加载某个页面的js文件,这样加载的资源减少,速度就更快。

代码分割主要做了两件事情:
1、将打包生成的文件分为多个js文件
2、按需加载,需要哪个文件就加载哪个文件。

多入口文件

entry:{
    main:'./src/main.js',
    app:'./src/app.js'
  },
   output:{
    // path 是所有文件输出的路径
    path:path.resolve(__dirname,'../dist'),// 当前文件的文件夹目录的dist下面
    filename:'static/js/[name].js',
    clean:true
  },

设置了多个入口文件,就会有多个输出文件。
但是如果多个文件中引入了公共的函数,我们可以发现打包后的两个js文件中都引入了一边。
我们希望,将公共的代码抽离出来,只需要写一次。

可以在webpack的配置文件中添加配置,官网介绍

optimization: {
    splitChunks:{
      chunks:'all',// 对所有模块都进行分割
      //修改配置
     cacheGroups: {// 组,哪些模块要打包到一个组
        default:{
          // 没有写的都是使用默认配置,单独写的会覆盖默认配置
          minSize:0 
        }
     }
     },
      /* 
      以下都是默认配置
      minSize:20000 分割代码最小的大小
      minRemainingSize: 0,// 类似于minsize,最后确保提取的文件大小不能为0,
      minChunks: 1,// 至少被引用的次数,满足条件才会代码分割
      maxAsyncRequests: 30,// 按需加较时并行加战的文件的最大数量
      maxInitialRequests: 30,// 入口js文件最大并行请求数量
      enforceSizeThreshold: 50000,// 超过5kb一定会单独打包(此时会忽略minRemainingSize
      cacheGroups: {// 组,哪些模块要打包到一个组
        defaultVendors:{ // 组名
          test: /[\V]node_modules[\V]/,// 需要打包到一起的模块 
          priority: -10,// 权重《越大越高》
          reuseExistingChunk: true,// 如果当前 chunk 包含已从主 bundle 中拆分出的模块
        },
        default:{// 其他没有写的配置会使用上面的默认值
          minChunks:2,// 这里的minChunks权重更大
          priority: -20,
          reuseExistingChunk: true.
        }
      }


     */
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin(),
      new TerserWebpackPlugin({
        parallel:threads
      })
    ],
  },

添加完配置之后再次打包,多了一些文件
在这里插入图片描述
按需加载
尽管我们实现了多模块输出,但是对于初始化时不需要加载的js文件,还是一次性加载了
例如countjs文件中的方法,仅仅在按钮点击时才会触发,我们希望能异步加载整个文件。

在这里插入图片描述
动态引入,将文件代码分割,拆分成单独的模块,在需要使用的时候自动加载
注意当调用 ES6 模块的 import() 方法(引入模块)时,必须指向模块的 .default 值,因为它才是 promise 被处理后返回的实际的 module 对象

document.getElementById("btn").onclick = function () {
  import('./js/count').then((res)=>{
    console.log(res.default(9,1),'res');
  })
  .catch((err)=>{
    console.log('模块引入失败',err);
  })
}

这样我们可以看到只有点了按钮后才会加载count文件,manjs中没有引入

在这里插入图片描述

管理打包输出的文件名
对于动态加载的文件
在这里插入图片描述
添加配置
少了个]
在这里插入图片描述
查看效果
在这里插入图片描述
所有type为asset 的资源都可以在 output中统一设置输出

 assetModuleFilename:'static/css/[hash:10][ext][query]',

preload、prefetch
前面已经做了代码分割,同时会使用import 动态导入语法来进行代码按需加载(路由懒加载就是这样实现的)
但是如果动态加载的资源比较大,用户会感觉到明显的卡顿。
所以我们希望浏览器在空闲的时候,能加载后续需要的资源、
preload: 告诉浏览器立即加载资源,但是并不执行。优先级更高。只能加载当前页面资源。兼容性大约92%
prefetch:告诉浏览器在空闲时间才开始加载资源。优先级低,可以加载当页面的也可以加载下一个页面的。兼容性大约72%

缓存
官网缓存介绍
我们将dist文件部署到服务器后,客户端就可以通过访问站点来获取资源,浏览器都使用了一种缓存技术。
然而,如果在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
我们可以给输出文件添加hash值,当内容变化再次构建时,hash会发生变化

 output: {
     filename: '[name].[contenthash].js',
      path: path.resolve(__dirname, 'dist'),
      clean: true,
    },

那如果什么也不改,hash应该不变吧?
还是变了!
为什么呢?

首页写我们先看下,在打包的时候想要把公共的模块提取出来,只加载一次。
将 optimization.runtimeChunk 设置为 true 或 ‘multiple’,会为每个入口添加一个只含有 runtime 的额外 chunk。
值 “single” 会创建一个在所有生成 chunk 之间共享的运行时文件。此设置是如下设置的别名:
在这里插入图片描述

由于像 lodash 或 react 这样的第三方库很少像本地源代码一样频繁修改,因此通常推荐将第三方库提取到单独的 vendor chunk 中。这一步将减少客户端对服务器的请求,同时保证自身代码与服务器一致。

   optimization: {
      runtimeChunk: 'single',
     splitChunks: {
       cacheGroups: {
         vendor: {
           test: /[\\/]node_modules[\\/]/,
           name: 'vendors',
           chunks: 'all',
         },
       },
     },
    },

这样可以大大减少mainjs 打包后的体积。

回到上面的问题,为什么没有什么改动hash也变化 了?
这是因为每个 module.id 会默认基于解析顺序(resolve order)增量。换言之,当解析顺序发生变化,ID 也会随之改变。简要概括便是:

main bundle 会随着自身的新增内容的修改,而发生变化。
vendor bundle 会随着自身的 module.id 的变化,而发生变化。
manifest runtime 会因为现在包含一个新模块的引用,而发生变化。

上面的第一点与最后一点都是符合预期的行为,而 vendor 的哈希值发生变化是我们要修复的。试试将 optimization.moduleIds 设置为 ‘deterministic’:

 optimization: {
     moduleIds: 'deterministic',

现在,不论是否添加任何新的本地依赖,对于前后两次构建,vendor 的哈希值都应保持一致

core-js
过去我们引用了babel对js代码进行兼容性处理,其中使用@babel/preset-env 智能预设来处理兼容性问题。
它能将es6的语法进行编译转换,但如果是async,promse等es6+的语法。它没办法处理。
此时我们的js代码依然存在兼容性问题。
core-js 是专门用老做es6 及以上api 的 polyfill(垫片)
就是用社区上提供的一段代码。让我们在不兼容某些特性的浏览器上能够兼容。
1、安装

npm i core-js

2、引入

import ‘core-js’

3、上面全部引入,体积太大,我们只想引入某一个

import “core-js/es/promise”

4、每次使用一个都需要手动引入吗,太麻烦了。我们希望它能够实现自动引入,使用了那个就自动引入那个
我们只需要在babel的配置文件中添加配置即可。

module.export = {
 presets: [['@babel/preset-env',{
  useBuiltIns:'usage',// 按需自动引入
  corejs:3 // corejs的版本
 }]]
}

PWA
什么是pwa ? 渐进式网络应用程序
一种可以提供类似于navtie app 体验的技术。
在离线状态下应用程序依然能够继续运行。
内部通过ServiceWorks 技术实现。
webapck 应该帮我们封装好了,我们只需要使用即可。
pwa的使用

使用过程中报错了
在这里插入图片描述
因为我们注册的文件在dist下面
我们可以下载一个专门用来部署静态资源服务器的库

npm i serve -g

安装好后,通过

serve dist

在这里插入图片描述
然后我们就可以看到效果了,设置为离线状态再加载页面,页面缓存了刚才的内容。

但是这个技术,目前兼容性并不好

webpack 优化总结
官网给的优化建议
总结
我们从 4 个角度对 webpack 和代码进行了优化:
一、提升开发体验
1、使用 source Map 让开发或上线时代码报错能有更加准确的错误提示。

二、提升 webpack 提升打包构建速度
1、使用HotModuleReplacement 让开发时只重新编译打包更新变化了的代码,不变的代码使用须存,从而使更新速度更快。
2、使用 oneof 让资源文件一旦被某个loader 处理了,就不会继续遍历了,打包速度更快。
3、使用 Include/Exclude 排除或只检测某些文件,处理的文件更少,速度更快。
4、使用 Cache 对 eslint 和 babel 处理的结果进行缓存,让第二次打包速度更快。
5、便用 Thead 多进程处理 eslint 和 babel 任务,速度更快(需要注意的是,进程启动通信都有开销的,要在比较多代码处理时使用才有效果)

三、减少代码体积
1、使用 Tree shaking 剔除了没有使用的多余代码,让代码体积更小。
2、使用 @babel/plugin-transfor-runtime 插件对 babel 进行处理,让辅助代码从中入,而不是每个文件都生成辅助代码,从而体积更小
3、使用 Image Minimizer 对项目中图片进行压缩,体积更小,请求速度更快。(需要注意的是,如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。)

四、优化代码运行性能
1、便用 code Split 对代码进行分割成多个js 文件,从而使单个文件体积更小,并行加载 js 速度更快。并通过 import 动态导入语法进行按需加载,从而达到需要使用时才加载该资源,不用时不加载资源。
2、使用 Preload / Prefetch 对代码进行提前加载,等未来需要使用时就能直接使用,从而用户体验更好。
3、便用 Network Cache 能对输出资源文件进行更好的命名,将来好做缓存,使用optimization.splitChunks 的cacheGroups 缓存第三方库,从而用户体验更好。
4、使用 core-js对js 进行兼容性处理,让我们es6+代码能运行在低版本浏览器。
5、使用 PWA 能让代码离线也能访问,从而提升用户体验。

在react-cli 中配置webpack
待学习

在vue-cli 中配置webpack
待学习

下面部分是原理,了解即可

loader 介绍
我们前面用到了各种各样的loader,他可以帮助webpack将不同类型的文件转换成webpack可以识别的模块。
loader的分类
1、pre 前置
2、normal 普通,默认
3、inline 内联
4、post 后置

执行顺序:pre > normal > inline > post

相同优先级的loader执行顺序为:从右到左,从下到上

使用loader的两种方式
1、配置方法

在这里插入图片描述

2、内联方式,在import 语法中显示指定loader
不想写了,放个截图吧,不推荐使用这种方式引入
在这里插入图片描述
定义一个简单的loader
定义
在这里插入图片描述
使用,相当于是一个函数
在这里插入图片描述
同步和异步loader

/* 
err d代表是否有错误
content 处理后的内容
source-map 继续传递给下一个loader
meta 参数传递给下一个loader
同步loader中不能进行异步处理
*/
module.exports = function (content,map,meta) {
  this.callback(null,content,map,meta)
  
};

// 异步loader
module.exports = function (content,map,meta) {
  const callback = this.async();
  setTimeout(()=>{
     callback(null,content,map,meta)
  },1000)

}

// raw loader 用于处理如本、字体等,接受的content 是buffer数据,二进制
function rawLoader (content,map,meta) {
   return content;
}
rawLoader.raw = true;
module.exports = rawLoader;

//pitch loader 优先于normal 执行,并且是从左到右执行
module.exports.pitch = function (content,map,meta) {
  return content;
}

loader API
更多关于api的介绍

我们需要了解的几个
在这里插入图片描述
自定义loader

// 自定义loader1
module.exports = function (content) {
  // 清楚文件内容中所有的console
  return  content.replace(/console\.log\(.*\);?/g,'');
}

还有一些pulgin的原理,不想看了,就学到这吧

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值