前端工程化解决方案之Webpack

学习目标:

◆ 能够说出什么是前端工程化
◆ 能够说出 webpack 的作用
◆ 能够掌握 webpack 的基本使用
◆ 了解常用 plugin 的基本使用(插件)
◆ 了解常用 loader 的基本使用(处理兼容性)
◆ 能够说出 Source Map 的作用(浏览器排错)


1. 什么是webpack?

  • 概念: webpack 是基于 node.js 开发出来的前端项目工程化的具体解决方案。
  • 主要功能: 它提供了友好的前端模块化开发支持,以及代码压缩混淆、处理浏览器端 JavaScript 的兼容性、性能优化等强大的功能。
  • 好处: 让程序员把工作的重心放到具体功能的实现上,提高了前端开发效率和项目的可维护性。
  • 注意: 目前 Vue,React 等前端项目,基本上都是基于 webpack 进行工程化开发的。

2. 实际开发中:

  • Vue项目中,使用 Vue-cli 一键生成带有 webpack 的项目。
  • 开箱即用,所有 webpack 配置项都是现成的!
  • 我们只需要知道 webpack 中的基本概念即可!

从一个小项目开始讲解【本文用到的命令,以及插件的版本可以自行参考相应的官方文档】

1. 初始化包管理配置文件package.json

  • 新建项目空白目录下运行如下命令,即初始化包管理配置文件 package.json
npm init –y
  • 新建 src 源代码目录。(这个目录是放程序员的源代码的)
  • 新建 src -> index.html 首页和 src -> index.js 脚本文件
  • 初始化首页基本的结构
  • 运行如下命令,安装 jQuery
npm    install jquery –S
  • index.js 通过 ES6 模块化的方式导入 jQuery
import $ from    'jquery'

发现,语法不兼容,这时候我们就需要用webpack来解决了。安装 webpack 相关的两个包。

2. 安装 webpack

(注:安装失败的话尝试用管理员身份安装 sudo npm i webpack )

npm    install webpack@5.42.1 webpack-cli@4.7.2 -D

但是,只安装不配置是不行的。

3. 配置 webpack

  • 在项目根目录中,创建名为 webpack.config.js 的 webpack 配置文件,并初始化如下的基本配置: 
// 对外暴露exports对象,添加mode对象成员
module.exports = {
   mode: 'development'
}

// mode 代表 webpack 运行的模式,可选值有两个 development 和 production
// 结论:开发用 development,追求的是打包的速度,而不是体积;
// 反过来,发布上线用 production,上线追求体积小,而不是打包速度快!
  • 在 package.json 的 scripts 节点下,新增 dev 脚本如下:
  "scripts": {
    "dev": "webpack",  // 代表运行 npm run dev 可以启动 webpack 打包
  }

这时候,运行 npm run dev 就可以打包 js 文件了,此时,index.html 引入的 js 文件应该改成打包后的js文件

4. 修改打包入口和输出路径

在 webpack 4.x 和 5.x 的版本中,有如下的默认约定:

  • 默认的打包入口文件为 src -> index.js
  • 默认的输出文件路径为 dist -> main.js

但是,打包入口文件和输出文件是可以在 webpack.config.js 中修改的,修改配置如下:

//记得先导入 path 模块
const path = require('path')

//在暴露对象中增加
module.exports = {
  // entry: '指定要处理哪个文件'
  entry: path.join(__dirname, './src/index1.js'),
  // 指定生成的文件要存放到哪里
  output: {
    // 想要存放的目录
    path: path.join(__dirname, 'dist'),
    // 想要生成的文件名
    filename: 'js/bundle.js'
  }

6. 安装 webpack 插件

在上面的修改代码过程中,需要频繁运行 npm run dev 重启 webpack 打包,这时候我们需要安装一下插件来实现自动监听代码修改,从而自动重启 webpack 打包了(类似于 node.js 中的 nodemon)

npm    install webpack-dev-server@3.11.2 -D

需要配置:

  •  修改 package.json -> scripts 中的 dev 命令如下:
"scripts" : {
  "dev" :    "webpack serve" ,     // 运行 npm run dev 
}
  • 此时,再次运行 npm run dev ,可以启动一个实时打包的 htpp 服务器,在浏览器中访问 http://localhost:8080 地址,查看自动打包效果

 

这时候,在文件中是看不到打包后的js文件的,因为配置了 webpack-dev-server ,打包文件存在内存中了,而且是虚拟的,而不是物理磁盘。此时,可以直接用 / 表示项目根目录,后面跟上要访问的文件名称,即可访问内存中的文件,如 /index.js (此时,index.html也应该改为引入这个路径下的js文件了

 

7. 安装 webpack 插件

到这里,我们可以通过访问 http://localhost:8080 查看开发页面,但是,每次点进去只看到文件目录文件夹,需要点击src文件夹才能访问页面,所以这时候就需要通过 html-webpack-plugin 这个插件复制一份 index.html镜像文件 到项目根目录了。

npm    install html-webpack-plugin@5.3.2 -D

需要配置 webpack.config.js 

// 1. 导入 html-webpack-plugin 这个插件,得到插件的构造函数
const HtmlPlugin = require('html-webpack-plugin')
// 2. new 构造函数,创建插件的实例对象
const htmlPlugin = new HtmlPlugin({
  // 指定要复制哪个页面
  template: './src/index.html',
  // 指定复制出来的文件名和存放路径
  filename: './index.html'
})


// 在这里增加 plugins节点 配置 htmlPlugin 插件,使插件生效
module.exports = {
   //插件的数组,将来 webpack 在运行时,会加载并调用这些插件
  plugins: [htmlPlugin]    //其实只有一个插件的时候可以不写数组形式
}

注:复制出来的inde.html也是看不见的,虚拟的,放在内存中的。

在 webpack.config.js 配置文件中,可以通过在 module.exports 中添加 devServer 节点对 webpack-dev-server 插件进行更多的配置,如下:

devServer: {
    // 首次打包成功后,自动打开浏览器
    open: true,
    // 在 http 协议中,如果端口号是 80,则可以被省略
    port: 80,
    // 指定运行的主机地址
    host: '127.0.0.1'
  }

注意:凡是修改了 配置文件,必须重启实时打包的服务器,否则最新的配置文件无法生效!

npm run dev

8. 安装louder插件

在实际开发过程中,webpack 默认只能打包处理以 .js 后缀名结尾的模块。其他非 .js 后缀名结尾的模块,webpack 默认处理不了,需要调用 loader 加载器才可以正常打包,否则会报错!

loader 加载器的作用:协助 webpack 打包处理特定的文件模块。比如:

  • css-loader 可以打包处理 .css 相关的文件
  • less-loader 可以打包处理 .less 相关的文件
  • babel-loader 可以打包处理 webpack 无法处理的高级 JS 语法

 

安装处理CSS文件的loader:

npm i style-loader@3.0.0 css-loader@5.2.6 -D

安装处理less文件的loader:

npm i    less -loader@10.0.1    less @4.1.1 -D

安装处理JS与打包处理样式表中与url路径相关的的loader:

npm i url-loader@4.1.1    file -loader@6.2.0 -D

以上三个loader的配置:在 webpack.config.js 的 exports 下的 module -> rules 数组中,添加 loader 规则如下:

module: {
    rules: [
      // 定义了不同模块对应的 loader 参数顺序必须按照下面
      { test: /\.css$/, use: ['style-loader', 'css-loader'] },
      // 处理 .less 文件的 loader
      { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
      // 处理图片文件的 loader
      // 如果需要调用的 loader 只有一个,则只传递一个字符串也行,如果有多个loader,则必须指定数组
      // 在配置 url-loader 的时候,多个参数之间,使用 & 符号进行分隔,这里顺便把打包的图片文件也指定了输出路径了,这里意思是小于470byte的图片文件才转为base64格式,否则加载原图片
      { test: /\.jpg|png|gif$/, use: 'url-loader?limit=470&outputPath=images' },
      // 使用 babel-loader 处理高级的 JS 语法
      // 在配置 babel-loader 的时候,程序员只需要把自己的代码进行转换即可;一定要排除 node_modules 目录中的 JS 文件
      // 因为第三方包中的 JS 兼容性,不需要程序员关心
      { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
    ]
  }

 

安装处理JS高级语法的loader:

npm i babel-loader@8.2.2 @babel/core@7.14.6 @babel/plugin-proposal-decorators@7.14.5 -D

配置:在项目根目录下,创建名为 babel.config.js 的配置文件,定义 Babel 的配置项如下:

module.exports = {
  // 声明 babel 可用的插件
  // 将来,webpack 在调用 babel-loader 的时候,会先加载 plugins 插件来使用
  plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]]
}

 

9. 项目打包发布配置

项目开发完成之后,需要使用 webpack 对项目进行打包发布,主要原因有以下两点:

  • 开发环境下,打包生成的文件存放于内存中,无法获取到最终打包生成的文件
  • 开发环境下,打包生成的文件不会进行代码压缩和性能优化

为了让项目能够在生产环境中高性能的运行,因此需要对项目进行打包发布。

因此,在 package.json 文件的 scripts 节点下,新增 build 命令如下:

  "scripts": {
    "dev": "webpack serve",  //项目开发用的命令
    "build": "webpack --mode production"  //项目发布打包运行 npm run build 命令
  }

注意:通过 --model 指定的参数项,会覆盖 webpack.config.js 中的 model 选项,也就是覆盖开发模式选项。

 

10. 模块化存放输出文件配置

但是呢,dist 文件内的各类文件最好模块化分类存放啦,这就需要一下配置了:

指定生成的 js 文件放在哪里,上面已经讲过了,在 webpack.config.js 配置文件的 output 节点中,进行如下配置:

  // 指定生成的文件要存放到哪里
  output: {
    // 存放的目录
    path: path.join(__dirname, 'dist'),
    // 生成的文件名
    filename: 'js/bundle.js'
  }

指定生成的图片文件放在哪:上面提示了。

 

11. 安装自动清理dist旧文件的插件

为了在每次打包发布时自动清理掉 dist 目录中的旧文件,可以安装并配置 clean-webpack-plugin 插件:

// 1、安装清理 dist 目录的webpack插件
npm i clean-webpack-plugin@3.0.0 -D

// 2.按需导入插件、得到插件的构造函数之后,创建插件的实例对象
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const cleanPlugin = new cleanWebpackPlugin()

// 3. 把创建的 cleanPlugin 插件实例对象,挂载到 plugins 节点中
plugins: [htmlPlugin,cleanPlugin],// 挂载插件

 

12. 了解Source Map

前端项目在投入生产环境之前,都需要对 JavaScript 源代码进行压缩混淆,从而减小文件的体积,提高文件的 加载效率。此时就不可避免的产生了另一个问题:对压缩混淆之后的代码除错(debug)是一件极其困难的事情,这时候就要认识一下 Source Map

开发环境下,webpack 默认启用了 Source Map 功能。当程序运行出错时,可以直接在控制台提示错误行的位置,并定位到具体的源代码但是

记录的是生成后的代码的位置。会导致运行时报错的行数与源代码的行 数不一致的问题。

 

解决默认Source Map问题:

开发环境下,推荐在 webpack.config.js 中添加如下的配置,即可保证运行时报错的行数与源代码的行数保持一致:

module.exports = {
mode: 'development',
    // eval-source-map 仅限在"开发模式"下使用,不建议在“生产模式”下使用。 
    // 此选项生成的 Source Map能够保证"运行时报错的行数"与"源代码的行数"保持一致 
    devtool:'eval-source-map',
    // 省略其它配置项... 
}

 

13. @根路径配置

路径问题,用@代表根目录配置 webpack.config.js:

module.exports = {
    resolve:{
        alias:{
            @:path.join(__dirname,'./src')
        }
    }
}

 

14. 打包发布省略Source Map

在生产环境下,如果省略了 devtool 选项,则最终生成的文件中不包含 Source Map。这能够防止原始代码通 过 Source Map 的形式暴露给别有所图之人。

  • 开发环境下:
    建议把 devtool 的值设置为 eval-source-map
    好处:可以精准定位到具体的错误行
  • 生产环境下:
    建议关闭 Source Map 或将 devtool 的值设置为 nosources-source-map
    好处:防止源码泄露,提高网站的安全性

 

 

posted @ 2022-04-08 21:57  RHCHIK  阅读(201)  评论(0编辑  收藏  举报