尝试配置一下简单的webpack?
准备
1.需要安装node.js
,当前教学版本为v12.22.12
2.一个IDE,这里使用vs code
,当前版本为v1.70.2
。
初始化一个项目
在一个位置,我们新建一个文件夹,并且进入该文件夹。
1 | mkdir webpack_study |
初始化一个node项目。
1 | npm init -y |
此时,在该目录下会有一个package.json文件
1 | . |
我们在根目录创建三个文件index.html
,index.js
,outside.js
。
1 | . |
index.html
内容如下:
1 |
|
index.js
内容如下:
1 | updateDom ('app','我是主页') |
outside.js内容如下:
1 | const updateDom = (id, content) => { |
我们打开这个index.html
。
思考问题
让我们思考几个问题。
如果在index.html
中调换 index.html
和 outside.html
,看看效果如何?
1 |
|
可见,如果不小心调换js的引用顺序,则会造成引用的函数没有先声明就使用了。
在本例子中,虽然文件只有两个,但是如果我们文件特别多,比如30个,50个,100个等等,那么就会存在一些声明重复,变量重复等等,这样会导致项目变得越来越臃肿,变得难以维护起来。所以,我们提出了一个新思路:模块化打包
。
因此,webpack
应运而生。
安装webpack
在文件根目录下,我们执行安装命令:
1 | npm i webpack webpack-cli -D |
-D 是开发依赖
安装完成后,执行一下命令查看是否有输出:
1 | npx webpack -v |
可以看到输入如下:
npx
是npm5.2之后提供的新功能。可以通过npx -v来检测它的版本。 在这里,我们通过它来调用项目安装的模块,它在运行时会在node_modules/.bin中去检查命令是否存在。webpack-dev-server
我们稍后再讲。
模块化代码
在把代码按照模块分割改动之前,我们先复原index.html
中的引用顺序,接着开始模块分割。即在outside.js
导出,在index.js
导入。下面我们来改造一下代码。这里使用commonjs规范
。如果你还不太了解,可以点击这里去阅读学习。
outside.js
1 | const updateDom = (id, content) => { |
index.js
1 | const {updateDom}=require('./outside') |
现在,我们来打开浏览器看一下:
报错了,模块没有定义。因为require
这种模块化的处理方式是无法在浏览器中运行的。这时,webpack
就派上用场了。
对index.js打包
我们在终端输入:
1 | npx webpack |
为了以后打包方便,我们可以在
package.json
配置好对应的启动脚本。可参考「这里」
输出的结果如下图所示。
我们查看当前的文件目录,如上图标注2
所示,你会发现多了一个dist
文件夹,里面有main.js
的一个js文件。
打开main.js
看一下,发现代码已经压缩了:
我们把压缩后的main.js
引入到index.html
中,然后在浏览器中打开看看。
浏览器不再报错,页面正常加载。
从最后的结果可看出,webpack
会分析入口文件中的引用关系,把相关的文件合成在一起,变成一个.js文件。
好啦,到了这里,我们已经开始入门了,接下来让我们深入了解一下webpack
。
webpack概念
webpack的核心概念如下所示,官网解释为
1 | webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。 |
这里我们现在不用全部着急着去理解所有的内容,一切先从实践中开始。当然,你可以点击对应的链接去官方文档阅读。不妨我们先从配置文件入手吧。
1.模式(mode)
像所有的软件一样,webpack也有自己的默认配置目录,这个配置文件就是webpack.config.js
。
我们先在项目根目录下创建一个名为webpack.config.js。其内容如下:
1 | module.exports={ |
这个文件的意义是导出一个配置项:用来对webpack的打包行为做设置。在操作层面,就是学习如何去使用这个文件。
上面的代码中,配置了打包方式,现在试着再打包一下,看看main.js
有什么变化。
1 | /* |
明显可以看到,main.js
比之前多出了很多内容,我们能够清晰的看到打包之前到源码。没错,这个是开发模式,不妨现在把mode调整成production
,再看看main.js
。
1 | (()=>{var e={810:e=>{e.exports={updateDom:(e,t)=>{window.document.getElementById(e).innerText=t}}}},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var p=t[o]={exports:{}};return e[o](p,p.exports,r),p.exports}(()=>{const{updateDom:e}=r(810);e("app","我是主页")})()})(); |
很明显,main.js
变得简洁起来,去掉了提示,同时也压缩了一些不必要的换行,加入了一定的混淆变量。
我们再换成**none
**试试:
1 | /******/ (() => { // webpackBootstrap |
看来,webpack
并没有把文件给压缩起来,他只是把两个文件放在了一起,没有像development
那样详细。
好啦,到这里,我们搞清楚了webpack
中的一个配置点mode,它有以下属性值:
- production. <– 默认值
- none.
- development.
2.入口(entry)
在webpack中,默认的入口和出口分别是:
- 默认入口是:
./src/index.js
- 默认输出是:
./dist/main.js
也就是说,如果直接在根目录下运行webpack
,它会直接去找.src
下的index.js
,并把打包之后的代码放在dist/main.js
下。没有dist
目录则会生成dist
目录。
我们在根目录新建一个src文件夹,并且把index.js
,outside.js
移动到它目录中:
1 | src |
在配置文件webpack.config.js
我们先不给它一个入口,保持默认:
1 | module.exports={ |
运行npx webpack
打包一下看看。
1 | npx webpack |
看来还是可以成功打包的。
但是,在实际的项目中,这种直接在默认目录的情况比较少。例如,js
全部都放在一个文件夹里,css
也是如此。
在src
目录下,我们新建一个js
文件夹,把两个js文件丢进去,并且把index.js
改名为main.js
:
1 | src |
接着,在webpack.config.js
的配置项中添加entry
项。
1 | module.exports = { |
重新打包试试看?🤓。
当然,entry
可以配置多个文件多个入口等,不过此笔记不做展开,等你读完这篇入门笔记之后,你可以去挑对应官方文档章节去阅读。
3.输出(output)
我们在webpack.config.js
中设置output
项:
1 | module.exports = { |
此配置将一个单独的 bundle.js
文件输出到 dist
目录中。
运行看看?
1 | main |
现在,我们制定一个输出位置:把出口文件设置为在build目录下的bundle.js。为此,webpack
就得这样配置:
1 | //引入nodejs中的核心模块 |
运行看看?
1 | build |
看来已经有啦。这里对路径说明一下,output
中的path
用来指定打包后的路径。注意:它必须是绝对路径
。所以,这里引用path模块中的join和__dirname来生成绝对路径。
如果path中的路径不存在,它会自动创建。
4.loader
在webpack
看来 一切皆模块,图片,样式文件,js文件。 但是webpack默认只能处理js模块,对于非js的内容,例如css, less文件,图片文件等等,它就需要一些帮手来处理了。这些帮手就是loader
。webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。你可以使用 Node.js
来很简单地编写自己的 loader。
例如,用css-loader
来处理css引入的问题。
css-loader
在src文件下,创建src/css/public.css 文件。
1 | body,html{ |
在src文件下,创建src/css/style.css 文件。
1 | @import "public.css"; |
css的
@import
语句用来导入另一个css文件。
最后,在src/js/main.js中导入css
1 | const {updateDom}=require('./outside') |
假如,我们没有加css-loader,我们打包看看,结果会得到如下报错:
上面报错的原因是:webpack把.css
文件内容当作了js代码来运行,那当然会报错了。所以,解决方法是安装相应的loader
来处理。
1 | npm i css-loader -D |
修改webpack.config.js
文件,添加module
。语法如下所示:
1 | //引入nodejs中的核心模块 |
更改一下html中引入的js代码。
1 |
|
运行一下,它不会报错。但是,页面上也并没有出现样式的效果。打包之后的文件中并没有包含css代码。
css
样式生效会有两种条件,通过<link>
和<style>
标签引用,而css-loader
只是能让你在.js中通过import来引入.css
,如果你希望引入的css代码最终以style标签的方式插入到html页面中,则还需要安装一个style-loader
。
style-loader
1 | npm i style-loader -D |
安装好后,修改配置webpack.config.js
1 | //引入nodejs中的核心模块 |
在有多个loader的情况下,use数组中的loader执行顺序是从右到左的过程。即:
- 先用css-loader来处理css
- 再用style-loader把css代码插入到html中的style标签中。
打包好之后,我们来看一下效果:
如图,css已经生效了。
Less-loader
假如,我们有less
文件在项目中,如果需要解析,我们需要安装less-loader
。
我们在src目录的less目录下创建 index.less。
1 | src |
内容如下:
1 | @import "../css/style.css"; |
因为我们直接把css给引入了,所以就在src/js/main.js中引入index.less
1 | const {updateDom}=require('./outside') |
接着,我们引入less-loader
1 | npm i less less-loader -D |
安装好后,在webpack.config.js
配置中添加对应的loader。
1 | //引入nodejs中的核心模块 |
在配置中,对于less文件的处理涉及三个loader,其处理顺序是less-loader => css-loader => style-loader。
less-loader:用来加载less文件,并处理成css
css-loader:用来加载css文件
style-loader:用来将css代码以style标签的格式插入到html文件中
好了,现在我们打个包,试一下效果如何。
less-loader生效了。
url-loader(可跳过)
我们处理完成了css,js,但是还差一个,文件。这里以图片为例,说明一下在 webpack
中图片的处理方法。
在src
文件下创建一个img
文件夹,并且引入一张图片:
1 | src |
接着,在less/index.less
中引入该图片。
1 | @import "../css/style.css"; |
执行一下打包,我们可以看到,在设置好的输出目录下有图片了。
假如我们想对该图片进行优化,例如压缩,重命名等等,我们可以引入url-loader
或file-loader
.
在当前文件根目录下执行:
1 | npm i url-loader file-loader -D |
在webpack.config.js
配置文件中设置如下:
1 | //引入nodejs中的核心模块 |
5.插件(plugin)
loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量等等。plugin是⽤于扩展webpack的功能,各种各样的plugin⼏乎可以让webpack做任何与构建相关关的事情。plugin的配置很简单,plugins配置项接收⼀个数组,数组⾥的每⼀项都是⼀个要使⽤的plugin的实例,plugin需要的参数通过构造函数传⼊。使⽤plugin的难点在于plugin本身的配置项,⽽不是如何在webpack中引⼊plugin,⼏乎所有webpack⽆法直接实现的功能,都能找到开源的plugin去解决,我们要做的就是去找更据⾃⼰的需要找出相应的plugin。
接下来我们就介绍一下常用的插件:
html-webpack-plugin
该插件能把我们⾃已写的.html⽂件复制到指定打包出⼝⽬录下,并引⼊相关的资源代码。为html⽂件中引⼊的外部资源如script、link动态添加每次compile后的hash,防⽌引⽤缓存的外部⽂件问题。可以⽣成创建html⼊⼝⽂件。
我们先安装它:
1 | npm i html-webpack-plugin -D |
之后,在webpack.config.js
中引入配置:
1 | //引入nodejs中的核心模块 |
配置好后,我们可以在输出目录中看到index文件啦。
1 | build |
1 |
|
到这里大家也发现了,在title位置它自己默认为Webpack App
,假如我们有自己想要的名字,能够配置嘛?答案是可以的。我们可以这样修改配置文件:
1 | plugins: [ |
当然,该插件的功能不仅仅只有这些,具体情况可以点击这里查看GitHub官方文档或者自行搜索对应的插件教程。
clean-webpack-plugin
clean-webpack-plugin是一个清除文件的插件。在每次打包后,磁盘空间会存有打包后的资源,在再次打包的时候,我们需要先把本地已有的打包后的资源清空,来减少它们对磁盘空间的占用。插件clean-webpack-plugin就可以帮我们做这个事情。
安装先:
1 | npm i clean-webpack-plugin -D |
配置一下webpack.config.js
1 | const path = require('path'); |
我们可以在打包目录下新建一些不需要的文件:
1 | build |
然后运行打包命令看看。
1 | build |
不要的文件已经清空了。
6.实时预览
我们使用vue-cli
脚手架的时候,当我们更新一下代码,脚手架会自动帮我们重新渲染,这个是因为脚手架自动帮我们重新发布并且更新。当然,核心离不开webpack-dev-server
。
我们来安装一下它:
1 | npm i webpack-dev-server -D |
接下来,在配置文件中添加如下信息配置:
1 | module.exports = { |
此外,我们配置一个专属脚本,用来启动该功能。找到packge.json
文件,加入脚本:
1 | { |
启动一下康康👀。
1 | npm run serve |