1. webpack是什么?
是一种前端资源构建工具,一个静态模块打包器
构建工具:将浏览器不认识的web资源,比如sass,less,ts等通过编译处理
静态资源打包器:将项目中静态资源,通过引用关系,将所有静态模块打包成一个或者多个bundle输出
通过loader转换文件,通过plugin注入钩子,最后输出多个模块组合成的文件
2.webpack 5个核心 (webpack.config.js)
a:Entry(入口) 类型:string,array,object
是指以哪个文件为入口起点开始打包,分析构建内部依赖图
1.单入口,打包形成一个trunk,输出一个bundle文件,trunk的名称默认是main.js
entry: "./src/index.js",
2.array方式:多入口
entry: ["./src/index.js", "./src/test.js"],
3.object:多入口 有几个trunk就输出几个bundle
entry:{
index:"./src/index.js",
test:"./src/test.js",
}
注意:
如果 entry 是一个 string 或 array,就只会生成一个 Chunk,这时 Chunk 的名称是 main
如果 entry 是一个 object,就可能会出现多个 Chunk,这时 Chunk 的名称是 object 键值对里键的名称。
配置动态 Entry:
entry: () => {
return {
a:'./pages/a',
b:'./pages/b',
}
};
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
b:Output(输出)
是指webpack打包之后的资源bundles输出到哪里去,以及如何命名
path:配置输出文件存放在本地的目录,必须是 string 类型的绝对路径
publicPath:配置发布到线上资源的 URL 前缀,为string 类型。 默认值是空字符串 '',即使用相对路径。
output: {
path: path.resolve(__dirname, "dist"), //默认 打包后的文件存放的地方
filename: "[name].js", //打包后输出文件的文件名 默认是main.js
publicPath:'https://cdn.example.com/assets/',
}
这时发布到线上的 HTML 在引入 JavaScript 文件时就需要:
<script src='https://cdn.example.com/assets/a_12345678.js'></script>
c:Loader (翻译)
处理那些非js文件,处理成自身理解的文件,从而进行打包
条件匹配:通过 test 、 include 、 exclude 三个配置项来命中 Loader 要应用规则的文件。
应用规则:对选中后的文件通过 use 配置项来应用 Loader,可以只应用一个 Loader 或者按照从后往前的顺序应用一组 Loader,同时还可以分别给 Loader 传入参数。
重置顺序:一组 Loader 的执行顺序默认是从右到左执行,通过 enforce 选项可以让其中一个 Loader 的执行顺序放到最前或者最后。
eg:
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader?cacheDirectory'],
include: path.resolve(__dirname, 'src')
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
exclude: path.resolve(__dirname, 'node_modules'),
},
{
test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
use: ['file-loader'],
parser: {
amd: false,
commonjs: false,
system: false,
harmony: false,
requireInclude: false,
requireEnsure: false,
requireContext: false,
browserify: false,
requireJs: false,
}
},
]
}
处理css 的loader css-loader---->引入css文件
cnpm install --save-dev style-loader css-loader
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader'],
}
]
}
常用的loader:
图片:file-loader
npm install --save-dev file-loader
{
test:/.(png|svg|jpg|gif)$/,
use:['file-loader']
}
sass: sass-loader
npm install sass-loader node-sass --save-dev
{
test:/\.scss$/,
use:['style-loader','css-loader?minimize','sass-loader'],
}
less: less-loader
npm install --save-dev less-loader less
{
test:/\.less$/,
use:['style-loader','css-loader','less-loader'],
}
babel: babel-loader 加载ES6及以上版本及jsx文件
npm install -D babel-loader @babel/core @babel/preset-env
{
test: /\.(js|jsx)$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
字体:file-loader和url-loader
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
d:Plugins(插件)
用于执行范围更广的任务,包括从打包优化和压缩,一直到重新定义环境中的变量等
eg:html-webpack-plugin:生成html文件
plugins: [
new HtmlPlugin(), // 默认的模板,打包之后生成一个index.html 文件
// 自定义设置模板
new HtmlPlugin({
title:'webpack test',
template:path.join(__dirname, './public/index.html') // 对应的模板地址
}),
]
e:Mode (模式)
指webpack使用相应的模式配置
分为2种模式:development (开发模式) production (生产模式)
webpack提供了一个webpack-dev-server工具给我们搭建本地运行环境。
cnpm i webpack-dev-server -D
在webpack.json 中配置对应的环境
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --open --port 3000 --hot --profile",
"dev": "webpack-dev-server ",
"build": "webpack"
}
则在开发环境上使用命令:npm run start 或者 npm run dev
生产环境进行打包操作:npm run build
f:使用 DevServer
提供 HTTP 服务而不是使用本地文件预览;
监听文件的变化并自动刷新网页,做到实时预览;
支持 Source Map,以方便调试。
在webpack.config.js 中配置:
devServer:{
contentBase: 'dist',
open:true,
port:4396,
hot:true,
hotOnly:true,
devtool:'source-map',
},
注意:存在版本一些兼容的问题 主要注意一下4个
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
g:Chunk:
代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
webpack相关问题
1.webpack与grunt、gulp的不同?
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
2.有哪些常见的Loader?他们是解决什么问题的?***
a:file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
b:url-loader:和file-loader 类似,但是能在文件很小的情况下以base64的方式把文件内容注入到代码中
c:source-map-loader:加载额外的source Map 文件,方便断点调试
d:image-loader: 加载并压缩图片文件
e:babel-loader:把es6转换成ES5
f:css-loader:加载css,支持模块化,压缩,文件导入等特性
g:style-loader:把css代码注入到js中,通过dom操作去加载css
h:eslint-loader:通过ESLint检查js代码
3.Loader和plugin的不同?
Loader:
可以理解为翻译器,因为webpack只能解析js文件,需要loader将非js 文件解析成webpack认识的文件
配置的位置是在:module.rules中配置,类型是数组,每一项是object 里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
Plugin:
插件,扩展webpack的功能,让webpack更加灵活,
配置的位置在:plugins中单独配置,类型是数组 每一项是一个plugin的实例,参数都通过构造函数传入。
4.webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全
1.初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
2.开始编译:参数初始化,加载配置插件,执行方法编译
3.确定入口:根据配置中的entry找到所有的入口文件
4.编译模块:从入口文件开始,调用所有配置的loader,以及对于的依赖关系,递归模块
5.完成模块的编译:得到编译之后的结果以及依赖关系
6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
5.webpack的热更新是什么?
热更新又称热替换(Hot Module Replacement),缩写为HMR,基于devServer,生产环境不需要devServer,所以生产环境不能用HMR功能
作用:
优化打包构建速度,一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度
样式文件:可以使用HMR功能,因为style-loader内部实现了
JS文件:默认没有HMR功能,需要修改js代码,添加支持HMR功能。入口文件做不了HMR功能,只能处理非入口js文件
HTML文件:默认没有HMR功能,同时会导致 html 文件不能热更新(即修改没有任何反应)
解决方案:
修改entry入口,将html文件引入
entry:['./src/js/index.js','./src/index.html']
6.如何利用webpack来优化前端性能?
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径
删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数--optimize-minimize来实现
提取公共代码。
开发环境下:
开启HMR功能,优化打包构建速度
配置 devtool: ‘source-map’,优化代码运行的性能
生产环境下:
1. oneOf 优化
默认情况下,假设设置了7、8个loader,每一个文件都得通过这7、8个loader处理(过一遍),浪费性能,使用 oneOf 找到了就能直接用,提升性能
2.开启 babel 缓存
当一个 js 文件发生变化时,其它 js 资源不用变
3.code split 分割
将js文件打包分割成多个bundle,避免体积过大
4.懒加载和预加载
5.WA 网站离线访问
6.多进程打包
开启多进程打包,主要处理js文件(babel-loader干的活久),进程启动大概为600ms,只有工作消耗时间比较长,才需要多进程打包,提升打包速度
7.dll 打包第三方库
code split将第三方库都打包成一个bundle,这样体积过大,会造成打包速度慢
dll 是将第三方库打包成多个bundle,从而进行速度优化
7.如何提高webpack的构建速度?
多入口情况下,使用CommonsChunkPlugin来提取公共代码
通过externals配置来提取常用库
利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
使用Happypack 实现多线程加速编译
使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度
使用Tree-shaking和Scope Hoisting来剔除多余代码
8.有哪些常见的Plugin?它们是解决什么问题的?***
html-webpack-plugin:可以复制一个有结构的html文件,并自动引入打包输出的所有资源(JS/CSS)
clean-webpack-plugin:重新打包自动清空 dist 目录
mini-css-extract-plugin:提取 js 中的 css 成单独文件
optimize-css-assets-webpack-plugin:压缩css
uglifyjs-webpack-plugin:压缩js
commons-chunk-plugin:提取公共代码
9.什么是Tree-shaking? 删除多余的代码
Tree-shaking可以用来剔除javascript中不用的死代码,它依赖静态的es6模块化语法,例如通过哦import 和export 导入导出,Tree-shaking最先在rollup中出现,webpack在2.0中将其引入,css中使用Tree-shaking需要引入Purify-CSS
10.模块化 CommonJS和 ES6 模块化?
CommonJS:通过 require 方法来同步地加载依赖的其他模块,通过 module.exports 导出需要暴露的接口
const moduleA = require('./moduleA');
module.exports = moduleA.someFunc;
ES6模块: 逐渐取代 CommonJS 和 AMD 规范 用import 导入 export default 导出
import { readFile } from 'fs';
import React from 'react';
export function hello() {};
export default {
};
11.构建工具做了哪些工作:
1.代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等。
2.文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。
3.代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
4.模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
5.自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器
6.代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
7.自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。