webpack-前端资源构建工具,静态资源打包器(moudle bundler)
文章目录
- webpack-前端资源构建工具,静态资源打包器(moudle bundler)
- 1 学习目标
- 2 资源构建工具/打包器是什么
- 3 webpack 五大核心 [官网文档](https://webpack.docschina.org/concepts/#entry)
- 4 处理es6
- 5 处理css ,less,scss,sass
- 6 处理图片 jpg,png,gif。。。
- 7 html-webpack-plugin插件打包资源放入html中
- 8 写一个vue文件打包
- 9 将css 提取成单独的css文件
- 10 手写一个Loader
- 11 手写一个plugin插件 [官网](https://webpack.docschina.org/api/compiler-hooks/#environment)
- 12 webpack 优化
- 12.1 production模式打包自带优化
- 12.2 css提取到单独文件 mini-css-extract-plugin [ctrl+click见上文](#jump)
- 12.3 postcss-loader autoprefixer添加代码前缀 [文档](https://webpack.docschina.org/loaders/postcss-loader/)
- 12.4 分析包的内容 插件webpack-bundle-analyzer [官方文档](https://www.npmjs.com/package/webpack-bundle-analyzer)
- 12.5 多入口打包,js优化,Code Spliting增加首屏响应速度
- 12.6 js 动态导入
- 12.7 提高构建性能
1 学习目标
- 知道webpack是干嘛的,核心组成
- webpack的主要配置文件
- webpack处理图片,css预编译语言,vue文件
- 使用空文件夹构建一个vue工程
- 了解webpack优化思路
2 资源构建工具/打包器是什么
- 处理js es6 -> es5 babel
- 处理css less/scss -> css loader
- 处理png、jpg。。。-> url-loader file-loader
- 一个大的工具来处理这些 —> webpack
3 webpack 五大核心 官网文档
-
entry -> 入口起点(entry point) 指示 webpack 应该使用哪个模块
-
output -> output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。
-
loader -> webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。
-
plugin -> loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。
Tip
-
mode -> 通过选择
development
,production
或none
之中的一个,来设置mode
参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为production
。npm i webpack webpack-cli
4 处理es6
npm install --save-dev babel-loader @babel/core @babel/cli @babel/preset-env
// .babelrc
{
"presets": [
"@babel/preset-env"
]
}
// webpack.config.js 添加loader
{
// 正则表达式匹配js文件
test: /\.js$/,
use: [
{
loader: 'babel-loader',
},
],
},
5 处理css ,less,scss,sass
npm i less-loader css-loader style-loader sass-loader
6 处理图片 jpg,png,gif。。。
npm i url-loader file-loader html-loader
7 html-webpack-plugin插件打包资源放入html中
npm i html-webpack-plugin
-
不配置任何选项的
html-webpack-plugin
插件,他会默认将webpack中的entry
配置所有入口thunk和extract-text-webpack-plugin
抽取的css样式都插入到文件指定的位置。例如上面生成的html文件内容如下:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack App</title> <link href="index-af150e90583a89775c77.css" rel="stylesheet"></head> <body> <script type="text/javascript" src="common-26a14e7d42a7c7bbc4c2.js"></script> <script type="text/javascript" src="index-af150e90583a89775c77.js"></script></body> </html>
-
配置自己的模板
plugins: [ // 详细plugins的配置 new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html' }) ],
8 写一个vue文件打包
npm i vue-loader vue-template-compiler @vue/compiler-sfc
// v15.*以上需要配置webpack的插件npm i vue-loader-plugin
"vue-loader": "^15.7.0",
// 和vue版本一致
"vue-template-compiler": "^2.6.14",
"webpack": "^5.4.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
// webpack配置文件中添加
const VueLoaderPlugin = require('vue-loader-plugin');
// plugins的配置
plugins: [
// 详细plugins的配置
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html'
}),
new VueLoaderPlugin()
],
// npm 报错处理
npm i --legacy-peer-deps
rules: [
// 详细loader配置
// 不同文件必须配置不同loader处理
{
test: /\.vue$/,
loader: 'vue-loader',
exclude:/node_modules/
},
]
-
文件夹部署vue注意事项
- 每个包之间的版本过高会报错
"vue-loader": "^15.7.0", "vue": "^2.6.14", "vue-template-compiler": "^2.6.14", "webpack": "^5.4.0", "webpack-cli": "^3.3.12", "webpack-dev-server": "^3.11.2" "css-loader": "^5.2.7", "html-webpack-plugin": "^5.3.2", "scss": "^0.2.4", "url-loader": "^4.1.1", "scss-loader": "^0.0.1", "style-loader": "^3.1.0", "postcss-loader": "^6.1.1", "vue-loader-plugin": "^1.3.0" "@vue/compiler-sfc": "^3.1.4", "file-loader": "^6.2.0", "html-loader": "^2.1.2",
- vue-loader v15.** 之后需要添加webpack插件解析vue文件
npm i vue-loader-plugin const VueLoaderPlugin = require('vue-loader-plugin'); plugins: [ // 详细plugins的配置 new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html' }), new VueLoaderPlugin() ],
9 将css 提取成单独的css文件
npm 下载插件
npm i mini-css-extract-plugin -D
// 配置plugin
// 插件配置
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
new MiniCssExtractPlugin({
//输出文件夹和文件名
filename:'static/css/built.css'
}),
// loader配置
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader进行处理
use: [
MiniCssExtractPlugin.loader,
'css-loader',
]
},
10 手写一个Loader
-
Loader实际上就是一个函数 入参source
module.exports= function(source) { // console.log(source) return source.replace(/我/g, '小明'); }
11 手写一个plugin插件 官网
-
plugin 生命周期 官方文档
-
手写一个HelloPlugin
- 一个具名javascrpit函数
- 在插件函数的prototype上定义一个apply方法
- 指定一个绑定到webpack自身的事件钩子
- chuliwebpack内部实力的特定数据
- 功能完成后调用webpack提供的回调
class HelloPlugin { constructor(options) { this.options = options } apply(compiler){ compiler.hooks.afterEmit.tap('HelloPlugin',compilation => { console.log('hello'); }) } } module.exports = HelloPlugin
-
Compiler和Compilation
compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境.
compilation 对象代表了一次资源版本构建。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
-
手写一个HTMLWebpackPlugin
- cheerio 官方文档
// html解析html npm i cheerio
const cheerio = require('cheerio'); const fs = require('fs'); class HTMLPlugin { constructor(options) { this.options = options } apply(compiler){ compiler.hooks.afterEmit.tap('HTMLPlugin',compilation => { // console.log(compilation.assets) let result = fs.readFileSync(this.options.template, 'utf-8'); let $= cheerio.load(result); // Object.keys(compilation.assets) Object.keys(compilation.assets).forEach(item => { if(/\.js$/.test(item)) { $(`<script src="./${item}"></script>`).appendTo('body'); } if(/\.css$/.test(item)) { $(`<link href="./${item}" rel="stylesheet">`).appendTo('head'); } }) // console.log($.html()); fs.writeFileSync('./dist/'+this.options.filename,$.html()) }) } } module.exports = HTMLPlugin
12 webpack 优化
12.1 production模式打包自带优化
-
tree shaking
打包时移除未引用代码dead-code,它依赖于ES6模块系统中的import和export
-
scope hoisting
将模块之间的关系进行结果推测,把打散的模块合并到一个函数。可以让webpack打包出来的代码文件更小,运行更快
-
代码压缩
所有代码使用UglifyjsPlugin插件进行压缩
12.2 css提取到单独文件 mini-css-extract-plugin ctrl+click见上文
12.3 postcss-loader autoprefixer添加代码前缀 文档
npm install --save-dev postcss-loader postcss-preset-env autoprefixer
// postcss.config.js
const autoprefixer = require('autoprefixer')({overrideBrowserslist: ['> 0.15% in CN']});
module.exports = {
plugins: [autoprefixer]
}
12.4 分析包的内容 插件webpack-bundle-analyzer 官方文档
npm install webpack-bundle-analyzer --save-dev
// 添加插件
// 分析包内容
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
// 开启 BundleAnalyzerPlugin
new BundleAnalyzerPlugin({
// 默认打开 端口号8000
// 设置为disabled 需要设置script脚本 "bundle-report": "webpack-bundle-analyzer --port 8123 dist/stats.json"
analyzerMode: 'server',
generateStatsFile: true,
statsOptions: {source: false}
}),
],
};
12.5 多入口打包,js优化,Code Spliting增加首屏响应速度
-
抽取公共代码 webpack4+ --> splitChunksPlugin插件—webpack 内置插件 官网
module.exports = { optimization: { splitChunks: { chunks: 'all' } } }
12.6 js 动态导入
-
webpack4+ 允许import语法动态导入,需要babel的插件支持 @babel/plugin-syntax-dynamic-import
npm i -D @babel/plugin-syntax-dynamic-import
-
修改.babelrc配置文件,添加插件,低版本浏览器需要添加es6.promis官方文档
{ "presets": ["@babel/env"], "plugins": [ "@babel/plugin-syntax-dynamic-import" ] }
-
静态导入 import 需要把import放到顶级作用域
import $ from 'juqery'
-
动态导入import写法
let a=1; if(a===1) { import('jquery').then(({ default: $ })=> { // TODO: }) }
-
12.7 提高构建性能
-
noParse 官网
防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 不应该含有
import
,require
,define
的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。例如引入一些第三方库时,比如jquery, bootstrap,其内部不会有其他模块的依赖。配置noParse跳过解析依 赖。
module: { noParse: /jquery|bootstrap/, rules: [ { test: /\.js/, use: {}, exclude: /node_modules/, //配置不包含哪些文件夹,loader会跳过这些文件夹 include: path.resolve(__dirname, 'src'), // 包含哪些文件夹,loader会从这些文件夹里解析 } ] }
-
IgnorePlugin 官网
IgnorePlugin 阻止为匹配正则表达式或过滤器函数的模块生成
import
或require
调用。在引入一些第三方模块时,例如moment,内部会做i18n国际化处理,所以会包含很多语言包,比较占空间,例如如果只用中文语言包,可以忽略所有的语言包,按需引入语言包,从而使构建效率更高,打包生成文件更小
-
首先找到moment所依赖的语言包是什么
import moment from 'moment' // 手动引用语言包 import 'moment/locale/zh-cn' // 设置语言国际化 moment.locale('zh-CN') console.log(moment().subtract(6,'days').calendar())
-
使用IgnorePlugin忽略其依赖
new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, });
-
需要使用某些依赖时手动引入
-
-
DllPlugin 官网
DllPlugin
和DllReferencePlugin
用某种方法实现了拆分 bundles,同时还大幅度提升了构建的速度。“DLL” 一词代表微软最初引入的动态链接库。此插件用于在单独的 webpack 配置中创建一个 dll-only-bundle。 此插件会生成一个名为
manifest.json
的文件,这个文件是用于让DllReferencePlugin
能够映射到相应的依赖上。