webpack的官方文档 https://webpack.js.org/
webpack的中文官方文档 https://webpack.docschina.org/
假设我们现在在做vue项目,那么我们需要加载哪些文件?
JavaScript的打包:
Css的处理:
资源文件img、font:
HTML资源的处理:打包HTML资源文件;
处理vue项目的SFC文件.vue文件;
1 | title:webpack到底是如何对我们的项目进行打包的呢? |
webpack的安装目前分为两个:webpack、webpack-cli
它们的关系:
执行webpack命令,会执行node_modules下的.bin目录下的webpack;webpack在执行时是依赖webpack-cli的,如果没有安装就会报错;而webpack-cli中代码执行时,才是真正利用webpack进行编译和打包的过程;
所以在安装webpack时,我们需要同时安装webpack-cli(第三方的脚手架事实上是没有使用webpack-cli的,而是类似于自己的vue-service-cli的东西)
1 | npm install webpack webpack-cli –g # 全局安装 |
1 | 在实际开发中我们通常使用**局部安装**的webpack |
安装之后可以直接使用npx webpack进行打包,但是这种打包方式有弊端——根目录下必须有一个src文件夹.
配置文件可以指定webpack打包的根目录,也可以指定生成的目录等
配置文件的名字是webpack.config.js放在项目根目录中,和node_modules同级
在这个文件中导出node模块
1 | const path = require('path') |
如果我们的webpack配置文件是别的名字,可以从脚本里面设置script,指定参数运行webpack
修改配置文件为 pack.config.js
package.json文件
1 | { |
然后可以直接运行 npm run build 直接使用指定文件打包
path模块用于对路径和文件进行处理,提供了很多好用的方法。
我们知道在Mac OS、Linux和window上的路径是不一样的:window上会使用 \或者 \ 来作为文件路径的分隔符,当然目前也支持 /;在Mac OS、Linux的Unix操作系统上使用 / 来作为文件路径的分隔符;
那么如果我们在window上使用 \ 来作为分隔符开发了一个应用程序,要部署到Linux上面应该怎么办呢,显示路径会出现一些问题,所以为了屏蔽他们之间的差异,在开发中对于路径的操作我们可以使用 path 模块;
==获取路径中的信息==
dirname:获取文件的父文件夹;
basename:获取文件名;
extname:获取文件扩展名
1 | const path = require('path') |
==路径的拼接==
如果我们希望将多个路径进行拼接,但是不同的操作系统可能使用的是不同的分隔符;
这个时候我们可以使用path.join函数;
1 | // 将多个路径拼接在一起 |
==绝对路径的拼接==
path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径;
给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径;如果在处理完所有给定path的段之后,还没有生成绝对路径,则使用当前工作目录;生成的路径被规范化并删除尾部斜杠,零长度path段被忽略;如果没有path传递段,path.resolve()将返回当前工作目录的绝对路径;
1 | const path = require('path') |
依赖图:
1 | 在使用webpack进行打包的时候,在js中只引入文件构建依赖图,而不导入资源,可以直接使用 `import "path"的形式` |
main.js
1 | import "./components/add_div.js" |
css/div.css
1 | .content{ |
components/add_div.js
1 | import "../css/div.css" |
执行命令 npm run build进行打包
上面的错误信息告诉我们需要一个loader来加载这个css文件,但是loader是什么呢?loader 可以用于对模块的源代码进行转换;
我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的;
在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的loader来完成这个功能;
那么我们需要一个什么样的loader呢?
对于加载css文件来说,我们需要一个可以读取css文件的loader,这个loader最常用的是css-loader;
css-loader的安装:
1 | npm install css-loader -D |
如何使用css-loader?
我们只讲配置方式,其他方式基本已经不再使用。
配置方式表示的意思是在我们的webpack.config.js文件中写明配置信息:
module.rules的配置如下:
[Rule][UseEntry]use: [ 'style-loader' ])是 loader 属性的简写方式(如:use: [ { loader: 'style-loader'} ]);Rule.use: [ { loader } ] 的简写。然后 npm run build构建项目
构建成功
打开src/index.html查看文件
1 |
|
1 | 注意:这里的script引入应该在body之后,以防引入js的时候,body还没有加载出来导致错误 |
我们已经可以通过css-loader来加载css文件了,但是你会发现这个css在我们的代码中并没有生效(页面没有效果)。
这是为什么呢?
因为css-loader只是负责将.css文件进行解析,并不会将解析之后的css插入到页面中;如果我们希望再完成插入style的操作,那么我们还需要另外一个loader,就是style-loader;
安装style-loader:
1 | npm install style-loader -D |
配置style-loader
那么我们应该如何使用style-loader:
注意:因为loader的执行顺序是从右向左(或者说从下到上,或者说从后到前的),所以我们需要将style-loader写到css-loader的前面;
如下,这样就可以了
安装less-loader工具
1 | npm install less-loader -D |
css/title.less
1 | @fontsize: 50px; |
add_div.js
1 | import "../css/div.css" |
1 | 一定不要忘了引入less文件 |
config.js
1 | const path = require('path') |
成果如图:
1 | 我们在开发的时候基本上不适用 autoprefixer,而是使用post-preset-env |
假设我们要设置css属性: user-select: none,该属性的作用是,用户鼠标悬浮在元素上的时候不显示任何交互动作(文字不能被选中和复制),但是这个属性在不同的浏览器中的设置是不一样的,比如 -ms-user-select:none,--webkit-user-select:none
我们需要一个工具,当我们设置了这个元素之后,自动帮我们添加上在不同浏览器上的属性,这个工具就是postcss(的autoprefixer插件)
安装post-css
1 | npm install postcss-loader -D |
webpack.config.js
安装autoprefixer插件
1 | npm install autoprefixer -D |
1 | use: [ |
div.css
1 | .content{ |
css中只写了一个user-select,但是构建完成的网站中显示如下:
webpack.config.js 中
另外在根目录创建文件 postcss.config.js
1 | module.exports = { |
同理
事实上,在配置postcss-loader时,我们配置插件并不需要使用autoprefixer。我们可以使用另外一个插件:postcss-preset-env
postcss-preset-env也是一个postcss的插件,它可以帮助我们将一些现代的CSS特性,转成大多数浏览器认识的CSS,并且会根据目标浏览器或者运行时环境添加所需的polyfill;也包括会自动帮助我们添加autoprefixer(所以相当于已经内置了autoprefixer);
首先,我们需要安装postcss-preset-env:
1 | npm install postcss-preset-env -D |
直接在postcss.config.js 中引入插件
1 | module.exports = { |
效果是一样的
加载图片有两种方式:
以前打包图片需要自己安装file-loader,但是现在用不着了,因为已经webpack已经为我们内置了。但是如果我们直接把图片import进来,会导致webpack把他认为是一个js模块,因此我们应该进行相应的配置来告诉webpack。
1 | { |
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:
测试:
拷贝一张图片到img中
add_div.js中新增
错误示范
1 | // 新增图片 |
正确示范
1 | import bird from "../img/bird.png" |
直接构建项目,成功
1 | asset/source 在开发中基本不适用,因此不解释了 |
add_div.js
增加一个小图片
1 | // 新增图片2 |
==asset/resource==
修改资源类型
重新构建
可以看到资源都指向了新生成的图片
因此这个方法是打包两张图片,每张图片都有自己的地址,并把网页中的地址自己的地址(新图片是用哈希算法生成的)
优点:js文件比较小,容易加载
缺点:需要多次发送请求,向服务器请求图片
==asset/inline==
修改资源类型
重新构建
可以看到图片使用base64编码进行内置到了元素里面。
同时js文件变得更大了(存储了图片的编码)
优点:不需要多次发送请求,向服务器请求图片
缺点:js文件比较大,不容易加载
==asset==
修改成asset之后
可以看见对于大图片,构建生成了新的图片并指向链接,而对于小图片,生成了base64编码提高了加载速度,大小图片的区分是有一个临界值的。
这个临界值,当然是可以自定义的:
webpack.config.js
1 | { |
==针对图片路径:==
1 | { |
[ext]: 处理文件的扩展名;[name]:处理文件的名称;[hash]:文件的内容,使用MD4的散列函数处理,生成的一个128位的hash值(32个十六进制);"img/[name].[hash:6].[ext]" 表示生成的文件放在img文件夹下面,文件名是原名.6位哈希加上原来的后缀名。
构建之后:
==针对所有资源路径:==
修改output,添加assetModuleFilename属性;
1 | output:{ |
1 | 我们在开发的时候基本上不适用 autoprefixer,而是使用post-preset-env |
Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript;包括:语法转换、源代码转换等
默认打包的时候,如果自己写的是es6,那么打包之后的代码也是es6代码,如果想要将es6的代码转化为es5的代码,应该使用babel
Babel配置方法和PostCSS极其相似。
首先安装babel-loader
@babel/core是babel的核心代码,必须安装;
@babel/cli是命令行使用babel的工具
1 | npm install @babel/cli @babel/core -D |
平时基本不用,略
1 | npm install @babel/preset-env -D |
webpack.config.js 中
1 | { |
另外在根目录创建文件 babel.config.js
1 | module.exports = { |
进行构建
变成了ES5的语法(const变成了var)
在src中创建文件夹src/vue_demo,创建文件App.vue
1 | <template> |
安装vue框架,因为开发和生产环境都要用到,因此直接安装
1 | npm install vue |
安装webpack进行解析的loader并配置
1 | npm install vue-loader |
webpack.config.js
vue项目比较特殊,需要引入一个插件:VueLoaderPlugin
1 | const {VueLoaderPlugin} = require('vue-loader/dist/index') |
main.js 中引入vue
1 | import { createApp } from "vue"; |
index.html中创建挂载点
1 | <body> |
项目构建
1 | npm run build |
成功
resolve用于设置模块如何被解析:
绝对路径
相对路径
模块路径
['node_modules'],所以默认会从node_modules中查找文件;如果是一个文件:
如果是一个文件夹:
extensions是解析到文件时自动添加扩展名:
['.wasm', '.mjs', '.js', '.json']另一个非常好用的功能是配置别名alias:
1 | resolve: { |
目的:
webpack提供的方法:
安装webpack-dev-server
1 | npm install webpack-dev-server -D |
打包好的东西不会放在磁盘中,不会写文件,而是直接放在内存中。
命令行为 webpack serve
在package.json中添加相关启动命令
启动成功
报错,要设置mode
在config文件中设置mode
再次启动,成功
什么是HMR呢?
HMR通过如下几种方式,来提高开发的速度:
如何使用HMR呢?
hot设置为true即可
有一个问题:在开发其他项目时,我们是否需要经常手动去写入 module.hot.accpet相关的API呢?
事实上社区已经针对这些有很成熟的解决方案了:
host默认是localhost,如果希望其他地方也可以访问,可以设置为 0.0.0.0
port设置监听的端口,默认情况下是8080
open是否打开浏览器:
compress是否为静态文件开启gzip compression: