前言

最近在跟着王红元大佬系统地学习构建模块的webpack。本次学习打算将最近学习到的所有内容做成一个系列的内容。整个系列是从零开始系统地学习webpack。系列文章是有先后顺序的,是按照我的学习路线去写的,所以按照顺序阅读效果效果更佳。

整个系列按照如下顺序:

这是本系列的第一篇:邂逅webpack

前端开发的复杂化

  1. 需要通过模块化开发;
  2. 在使用ES6、TypeScript、less、sass等技术时,浏览器是不认识这些代码的,必须经过编译转化为浏览器可以执行的代码;
  3. 在开发时,我们需要监听代码的变化,然后实时地反映到浏览器上;
  4. 开发完成后,需要将代码进行压缩、合并以及其他优化。

    1. .....

学习原因

以上这些都是在开发过程中需要考虑到的问题。但是实际上,我在开发中好像并不需要手动地去进行配置,这些问题好像已经给自动配置好了。

这是因为,当下的项目基本都是基于三大主流框架进行开发。而在创建项目时,是用脚手架创建的,比如vue-cli、create-react-app脚手架。而这些脚手架,在底层已经使用webpack配置好了。

那我们直接拿脚手架来用不就好了,为啥还需要学习webpack呢?

学会了webpack,我们可以在脚手架的基础上添加想要的配置。比如说最近我在React框架上用到less,但是create-react-app是默认不支持less的,所以只能手动配置。脚手架只是做了很多通用的配置,但是现实开发中会出现很多需要个性化的配置。所以一个项目想做到百分百满足需求还是需要我们手动去构建出来。

定义与解析

让我们看看官方对webpack的定义是什么?

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。

解析下定义:

  1. 打包器:webpack就是一个打包工具。
  2. 静态:可以从官方给出的图看出,我们开发时写的各式各样的文件,都会转化为STATIC ASSETS静态资源。静态资源在后续会部署到静态服务器上,浏览器就可以从静态服务器拿到静态资源然后下载解析了。
  3. 模块化:webpack默认支持各种模块化开发,比如ES Mouele、CommonJS、AMD等。(新版本的浏览器默认只支持ES Module,而旧版本是不支持所有模块化的。有了webpack我们就可以自行选择想要的模块化方案,无需担心浏览器支不支持。)

977a0d8e785bcd51c835fababf942222.png

常见使用场景

这里简单说下一些常见的使用场景,后续再深入进行学习。

  • 开发时:比如说给某些目录结构起别名、让项目支持less等预处理器、让项目支持TypeScript等;
  • 优化时:比如说安装性能分析工具、使用gzip压缩代码、引用cdn的资源、抽取公共代码等;

Webpack的基本使用

安装

需要安装:webpack、webpack-cli

  1. npm install --save-dev webpack
  2. //如果你使用 webpack 4+ 版本,你还需要安装 CLI。
  3. npm install --save-dev webpack-cli

使用

Webpack会把 ./src/index.js 文件作为入口,然后将所有依赖的文件,递归地构建一个依赖图,最后根据依赖图进行打包。如果没有依赖的文件,是不会打包的。

  1. //方式一
  2. // 终端输入命令,npx会到node_modules的bin文件夹下找安装好的webpack
  3. npx webpack
  4. //方式二
  5. //首先在package.json配置
  6. "script":{
  7. "build":"webpack"
  8. }
  9. //然后终端输入命令
  10. npm run build

配置

在根目录下创建配置文件webpack.config.js

  1. //webpack.config.js
  2. const path = require('path')
  3. //使用CommonJs模块化,因为是在node环境执行
  4. module.exports = {
  5. //配置入口:这里的相对路径其实不是相对与当前文件,而是相对于context这个属性
  6. entry = './src/main.js',
  7. //配置出口,其中path必须为绝对路径,相对路径会报错。(这里__dirname为当前文件所在目录下的完整绝对路径)
  8. output = {
  9. filename: 'bundle.js',
  10. path: path.resolve(__dirname,"./build")
  11. }
  12. }

更改配置文件名字或位置:
Webpack在打包时会默认到根目录上看看有没有配置文件webpack.config.js。如果我们想要给配置文件换个名字,或者换个位置,webpack就找不到了。解决方法也很简单,如下:

  1. //package.json
  2. "script":{
  3. "build":"webpack --config './config/webpack.common.js'"
  4. }

Webpack核心之一:loader

先引用官方对loader的解释

  1. loader 用于对模块的源代码进行转换。loader 可以使你在 import "加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URLloader 甚至允许你直接在 JavaScript 模块中 import CSS文件!”
  • 看完我们就大致明白了,loader就是对我们特定的模块进行转化。针对不同的模块,对应的loader会对我们的模块进行转化:
  • 一些模块会转化为js直接统一打包到出口js文件;
  • 一些会转化为资源文件打包到出口文件夹下。

使用

对于Loader的配置,这里以处理css文件为例:
我们要打包的依赖的文件要是有个css文件,那会正常打包吗?答案是不会的。因为css文件的打包需要用到另一个核心——loader
首先需要下载需要的loader:

  1. npm install --save-dev css-loader
  2. npm install --save-dev ts-loader

loader的使用方式分为三种。

方式一:内联

  1. import Styles from ‘style-loader!css-loader?modules!./styles.css’;

方式二:CLI(不推荐,在webpack@5已经不支持)

方式三:通过配置文件(推荐)

  1. //webpack.config.js
  2. module: {
  3. rules: [
  4. {
  5. //根据正则匹配资源
  6. test: /\.css$/,
  7. //use是一个可以接受多个loader对象的数组,loader编写顺序从后往前
  8. use: [
  9. { loader: 'style-loader' },
  10. 'css-loader',
  11. ]
  12. },
  13. {
  14. test: /\.less$/,
  15. use: [
  16. 'style-loader',
  17. { loader: 'css-loader',
  18. options:{
  19. importLoaders: 2
  20. }
  21. },
  22. 'postcss-loader',
  23. 'less-loader',
  24. ]
  25. }
  26. ]
  27. }

通过上述任一方式,配置好了css-loader与style-loader,就可以正常打包css文件了。

(这里还有个注意点,css-loader负责加载css文件,而style-loader负责将css文件绑定到js文件上,那很容易推导出css-loader是比style-loader先执行的。那为什么在配置时将css-loader放在下边呢?这是因为编译loader时都是从下往上处理的。)

对于项目中基本上都需要配置到的常用的loader,可以到另一篇学习总结中查看:webpack中常用的loader

Webpack另一核心:plugins插件

老样子,先看下官方对plugins的解释

loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。

这样看来,plugins其实就是loader的黄金搭档,专门处理loader无法实现的事情。就比如打包优化、资源管理、环境变量注入等。
这里先演示几个实用常用的plugins,帮助我们了解plugins。然后再深入总结一些常用的plugins。

HtmlWebpackPlugin、

安装:

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

使用:

  1. //webpack.config.js
  2. const HtmlWebpackPlugin = require('html-webpack-plugin');
  3. plugins: [
  4. new HtmlWebpackPlugin({
  5. title: "coderwhy webpack",
  6. template: "./public/index.html"
  7. }),
  8. ]

HtmlWebpackPlugin:在之前的打包中,我们是可以把依赖到的模块都打包到出口文件夹下的,但是却少了一个非常重要的文件:index.html。那我们得手动加一个html文件然后Script标签手动引入打包出来的js文件?这显然很不合理。因此就可以使用HtmlWebpackPlugin来帮助我们完成。

图片2.png图片3.png

HtmlWebpackPlugin是怎么实现的呢?HtmlWebpackPlugin帮助我们自动生成index.html文件(并且会自动帮我们引入打包后的js文件),但是这个html文件又是哪里来的呢?我们可以到node_modules文件夹下找到HtmlWebpackPlugin的源码,然后我们就可以发现,原来HtmlWebpackPlugin是引用了ejs模板(一个基本的html文件模板)。下边让我们来看一看ejs模板:

图片4.png

现在我们就知道原来index.html是这样生成的。

既然html的文件是依据ejs模块生成,那我们能不能使用自己的模板呢?
毕竟我们也是需要加自己的东西的,比如说我们需要使用cnd外链的方式导入第三方库,或者在vue项目里,所有的组件都会挂载到一个

标签上等情况。
那我们看看vue-cli是怎么做的吧。打开一个用vue-cli搭建的项目,我们就可以发现vue-cli是在public文件夹下写了一个index.html模板,然后webpack.config.js里配置了HtmlWebpackPlugin的options里的component。这样就可以使用自己的模板创建index.html了。

其它注意点:

  1. plugin都是使用new去生成的:实际上每一个plugin都是一个类,所以需要用new关键字去生成plugin。
  2. require导入时有的用到了解构赋值有的不需要:这是因为每一个plugin的导出方式都不太一样。需要根据导出方式决定要不要使用解构。

其他的一些项目中基本都需要配置到的常用的plugins,放到了另一篇学习总结上:webpack中常用的loader