webpack
什么是Webpack
官方解释:
webpack is a static module bundler for modern JavaScript applications.
翻译一下:webpack是一个静态的模块化打包工具,为现代的JavaScript应用程序;
我们来对上面的解释进行拆解:
- 打包bundler:webpack可以将帮助我们进行打包,所以它是一个打包工具;
- 静态的static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器);
- 模块化module:webpack默认支持各种模块化开发,ES Module、CommonJS、AMD等;
- 现代的modern:现代前端的开发越来越复杂,催生了webpack的出现和发展;
即:无论开发使用什么语言,最终通过webpack将代码打包成普通的静态资源(详见下文:Webpack依赖图);
环境
Webpack的运行是依赖Node环境的,所以我们电脑上必须有Node环境;
安装
webpack的安装目前分为两个:webpack(代码使用)、webpack-cli(命令行使用);
这里推荐局部安装:假如电脑上有3个项目:vue2,vue3,react;三个项目都需要打包,可能依赖的webpack版本不一样;
所以:应该每个项目有着自己的webpack,需要用什么版本,在本地的局部环境安装对应的webpack版本即可;
1 | npm install webpack webpack-cli –g # 全局安装(不推荐) |
基础打包
默认打包
- 创建个文件夹,使用
npm init -y
创建package.json; npm i webpack webpack-cli -D
安装局部环境依赖;- 在根目录下新建
src
文件夹,文件夹下新建入口文件index.js
,写入任意js代码; - 在根目录下
cmd
:通过npx webpack
进行打包==>打包成功:根目录下生成dist
文件夹,下面有main.js
;(可以将此打包之后的js引入html中,可以正常运行); - 但是如果根目录下没有
src
文件夹(其他名字的文件夹也不行),或者src
文件夹下的js不叫index.js
进行打包==>打包失败;(即:文件夹必须叫src,入口文件必须叫index.js); - 那如果就不想有src文件夹或index.js如何进行打包呢?这里用到了配置参数;
配置参数
修改文件夹名为location,下面js改为main.js;
- 指定入口;
1 | npx webpack --entry ./location/main.js #-entry为入口文件的意思, 后面跟 入口文件的路径; |
如何修改打包之后的文件夹名和下面的js名呢?
- 指定输出文件夹名、输出文件名;
1 | npx webpack --entry ./location/main.js --output-filename fsl.js --output-path fsllala |
但是这样写配置参数,太长了,不方便,如何解决呢?==>单独创建配置文件;
配置文件
在根目录下新建
webpack.config.js
(固定名字),里面进行参数配置;
此时目录结构如下:
1 | |—— node_modules |
webpack.config.js
其实是个模块,webpack的运行环境为nodejs
,nodejs
会将该模块导出的内容进行读取;所以需要使用node的CommonJs;不能使用ES6模块,即:
1 | // webpack.config.js文件 |
- 进行相关参数配置
1 | const path = require("path"); |
- 如果不想叫
webpack.config.js
,而是叫vue.config.js
,运行npx webpack
==>报错;
1 | npx webpack --config vue.config.js # 通过指定配置文件名,可以解决 |
npm run build
是怎么做到打包的呢
1 | // package.json |
进阶打包
Webpack依赖图
webpack到底是如何对我们的项目进行打包的呢?
- 事实上webpack在处理应用程序时,它会根据命令或者配置文件找到入口文件;
- 从入口开始,会生成一个 依赖关系图,这个依赖关系图会包含应用程序中所需的所有模块(比如.js文件、css文件、图片、字 体等);
- 然后遍历图结构,打包一个个模块 (webpack默认只给JS文件打包,别的文件需要根据文件的不同使用不同的loader来解析);
loader
新建目录结构如下:
1 | |—— node_modules |
验证loader作用
验证上问提及:webpack默认只给JS文件打包,别的文件需要根据文件的不同使用不同的loader来解析;
期望效果:
- index.html 文件中仅引入打包之后的入口文件,别的不做任何操作;
- 页面展示有css样式的内容;
编写验证代码
- css文件夹下新建div_style.css
1 | /* css/div_style.css */ |
- components文件夹下新建div_cpns.js
1 | // components/div_cpns.js |
- 入口文件引入div_cpns.js
1 | // src/index.js |
- 使用
npm run build
进行打包
1 | # package.json |
打包出错,打包结果如下图所示:
上面的错误信息告诉我们需要一个loader来加载这个css文件,但是loader是什么呢?
- loader 可以用于对模块的源代码进行转换;
- 我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的;
- 在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的loader来完成这个功能;
- webpack默认支持对js文件的处理;其他文件需要根据文件的不同使用不同的loader来解析;
css-loader与style-loader
- css-loader:可以解析css文件的loader。但该loader并不会将解析之后的css插入到页面中,即如果只使用该loader会产生css解析完了,但是页面没有效果的现象;
- style-loader:会将解析之后的css插入到页面,即完成插入style的操作;
loader下载:
1 | npm install css-loader style-loader -D #loader其实都是研发环境的,生产环境都是解析之后的静态文件; |
loader配置
- webpack.config.js文件中的module.rules中允许我们配置多个loader;
- module.rules的配置如下:
- rules属性对应的值是一个数组,数组中存放的是一个个的Rule,Rule是一个对象,对象中可以设置多个属性:
- test属性:用于对 resource(资源)进行匹配的,通常会设置成正则表达式;
- use属性:对应的值是一个数组,数组里为各种loader;注意:loader的执行顺序是从后往前的;
- use属性数组内可以为对象,对象属性为:
- loader:必须有一个 loader属性,对应的值是一个字符串;
- options:可选的属性,值是一个字符串或者对象,值会被传入到loader中
- query:目前已经使用options来替代;
- use属性数组内可以为字符串,是 loader 属性的简写方式;
- rules属性对应的值是一个数组,数组中存放的是一个个的Rule,Rule是一个对象,对象中可以设置多个属性:
1 | module.exports={ |
使用npm run build
进行打包==>打包成功;
index.html引入打包之后的文件,查看效果:
1 | <script src="./dist/main.js"></script> |
less-loader
less同理,环境不支持该预处理器,需将现将less、sass等编写的css需要通过工具转换成普通的css;
loader下载
1 | npm install less-loader -D |
配置webpack.config.js
1 | module.exports={ |
PostCSS
参考文献:PostCss,PostCSS真的太好用了!
loader下载
1 | npm install postcss-loader -D |
autoprefixer
- 有一些css属性存在浏览器兼容问题,需要开发手动添加浏览器前缀;
- 而Autoprefixer将使用基于当前浏览器支持的特性和属性数据去为你自动添加前缀(-webkit-,-ms-,-moz-)。你可以尝试下Autoprefixer的demo:Autoprefixer CSS online
使用postcss插件Autoprefixer:
- 下载
1 | npm install autoprefixer -D |
- 设置单独的postcss配置文件:根目录下,新建
postcss.config.js
( 注意:因为postcss需要有对应的插件才会起效果,所以我们需要配置它的plugin);
1 | // postcss.config.js |
- 设置loader
1 | // webpack.config.js |
- 相关css代码
1 | /* css/div_style.css */ |
npm run build
进行打包,index.html引入打包之后的文件,检查css- 效果如下
postcss-preset-env
- 集成了postcss常用的插件(Autoprefixer,polyfill……);
- 所以用postcss-preset-env,就不需要安装使用Autoprefixer了,因为内部已经集成了Autoprefixer;
使用postcss插件postcss-preset-env同Autoprefixer步骤;
Webpack打包图片
asset module type
我们当前使用的webpack版本是webpack5:
- 在webpack5之前,加载这些资源我们需要使用一些loader,比如raw-loader 、url-loader、file-loader;(需要下载对应的loader,然后使用)
- 在webpack5开始,我们可以直接使用资源模块类型(asset module type),来替代上面的这些loader;(不需要下载loader)
**资源模块类型(asset module type)**,通过添加 4 种新的模块类型,来替换所有这些 loader:
- asset/resource 发送一个单独的文件并导出 URL;(之前通过使用 file-loader 实现)
- asset/inline 导出一个资源的 data URI;(之前通过使用 url-loader 实现)
- asset/source 导出资源的源代码(基本不用);(之前通过使用 raw-loader 实现)
- asset在导出一个 data URI 和发送一个单独的文件之间自动选择;(之前通过使用 url-loader,并且配置资源体积限制实现)
asset module type的使用
- 新建文件夹img,用于存放图片;
- 在components下,新建img_cpns.js;
1 | // src/components/img_cpns.js |
- 在入口文件里面引入img_cpns.js,构成webpack的依赖图结构;
1 | // src/index.js |
- webpack5版本开始,不需要下载资源loader,只需要配置asset module type即可;
将图片全部转换为一个单独的文件
- 配置webpack
1 | // webpack.config.js |
- 通过
npm run build
进行打包;观察打包之后的dist文件夹;**(每次打包前需要删除之前的dist文件夹,防止之前的分包依旧保留,后续可以通过配置实现自动删除)**
发现将原来的ikun.jpg,打包成了1d40d06e317136088c5a.jpg;然后main.js对打包之后的图片地址做了处理;
- 浏览器运行,可看到图片正常显示,图片地址为在线地址:http://127.0.0.1:5500/dist/1d40d06e317136088c5a.jpg
如何做到自定义输出文件名呢?
自定义输出文件名:官网
- 配置webpack
1 | module.exports = { |
通过npm run build
进行打包;观察打包之后的dist文件夹;**(每次打包前需要删除之前的dist文件夹,防止之前的分包依旧保留,后续可以通过配置实现自动删除)**
发现将原来的ikun.jpg,打包成了:ikun_1d40d06e317136088c5a.jpg;
如何将图片资源放到一个单独的文件夹内呢?
- 配置webpack
1 | generator: { |
将图片全部转换为base64格式;
优点:相比较于 asset/resource,少发送(图片加载)网络请求;
缺点:造成JS文件偏大,下载JS文件、解析本身消耗时间非常长==>造成代码阻塞;
配置webpack
1 | module.exports={ |
- 通过
npm run build
进行打包;观察打包之后的dist文件夹;**(每次打包前需要删除之前的dist文件夹,防止之前的分包依旧保留,后续可以通过配置实现自动删除)**
发现dist文件夹里面只有一个main.js;
- 浏览器运行,可看到图片正常显示,图片地址为base64:data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD…P2atuIjKPvHtU5hxbHHVqzLS6xGJv4G6CtISEIPRulecZn//Z
可通过合理的配置,决定图片的转化;
合理的配置:
小一点的图片:进行base64编码;
大一点的图片:单独的图片打包,形成url地址,单独的请求这个url图片;
配置webpack:官网
1 | module.exports = { |
Babel
- webpack可以打包JS文件,但是ES6+的语法不会转化为ES5;
- Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript;
- 包括:ES6+,TypeScript、Vue、React等通过Babel转换为向后兼容版本的JavaScript;
- 在线Babel转换:官网
插件
Babel的使用,需要安装相应的插件(这里不过多介绍,一般来说安装预设preset即可);
1 | # 基本不安装此插件 |
Babel的预设preset
集成了Babel常用的插件;
- 安装
1 | npm install @babel/preset-env -D #安装预设preset |
- 使用
1 | //webpack.config.js |
1 | // 新建babel.config.js |
- 入口文件
1 | // // src/index.js |
- 打包
npm run build
,查看打包之后的main.js;(箭头函数转化为了普通函数)
1 | "hello babel".split(" ").map((function(l){return console.log(l)})); |
Plugin
- Loader是用于特定的模块类型进行转换;(文件解析、转换)
- Plugin可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等;(文件解析、转换之外的所有事情);
- 官网
CleanWebpackPlugin
每次修改了一些配置,重新打包时,都需要手动删除dist文件夹,CleanWebpackPlugin可以自动化删除(需要配置输出目录)。
Tip:5.20.0+的版本,可以直接配置output==>官网
- 安装
1 | npm install clean-webpack-plugin -D |
- 配置
1 | const path = require("path"); |
- 测试
在之前打包的dist文件夹中,随便新建个文件,比如abc.js==>打包之后被清除;