- 从零构建typescript项目时的webpack工程化技术知识整理。(从我的印象笔记中迁移过来,篇幅过大,分章节整理与分享)。
- 项目demo源码就不贴了,从零构建才能有所得,遇到问题想办法解决才能进步。
目录
- 1、启动css、scss、less的module加载编译
- 2、使用动态html模板
- 3、设置常用全局依赖变量($,_,lodash,React等等)
- 4、使用css压缩
- 5、配置动态文件输出地址(完整拼接文件前缀,非'/'相对路径)
- 6、编译和打包进程进度状态bar显示
- 7、打包时将静态资源移动到指定文件夹下
- 8、设置输出js文件的hash命名
- 9、设置输出css文件的hash命名,(压缩模式下)
- 10、模块解析:引入文件时可以文件名可以不带后缀
- 11、配置便捷路径
- 12、设置默认导出
- 13、指定打包或编译后的分包文件名称
- 14、ts环境如何import引入多媒体资源,png、jpg、svg...
- 15、添加webpack编译热更新功能
- 16、webpack启动命令:指定配置js文件
- 17、启动命令:指定开发模式启动
- 18、分割webpack配置
- 19、性能优化--减小lodash体积
- 20、性能分析--性能分析插件
- 21、Antdesign 4安装和按需加载优化配置
- 22、性能优化-减少编译体积大小-减小moment体积
- 23、构建优化-将大型库外链 && 将库预先编译
- 24、构建优化-使用缓存提高编译速度和打包速度
- 25、构建优化-使用缓存插件极大提升编译和打包速度
- 26、构建优化-并行打包
- 27、构建优化-externals-将公共依提取出来不打包,通过script加载
1、启动css、scss、less的module加载编译
- rules配置
{
test: /\.(c|sc|sa)ss$/,
include: path.resolve(__dirname, './src'), // 提升d.ts的索引速度
use: [
process.env.BABEL_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: '@teamsupercell/typings-for-css-modules-loader', // 自动生成scss.d.ts文件
options: {
formatter: "prettier", // 优化d.ts代码
}
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[local]_[name]-[hash:base64:4]',
},
sourceMap: true,
importLoaders: 2,
localsConvention: 'camelCase'
},
},
'sass-loader', // 如果是less就是用less-loader
{
loader: "postcss-loader",
options: {
ident: "postcss", // postcss-loader中options里使用了function、require时需要ident属性,可以是任意值
plugins: () => [
require("postcss-flexbugs-fixes"), // 修复flex弹性盒子bug
require("autoprefixer")("last 100 versions"), // css前缀浏览器自动兼容
]
}
},
]
}
- 由于模块化scss会生成scss.d.ts声明文件,所以需要自动忽略文件
new webpack.WatchIgnorePlugin([
/css\.d\.ts$/,
/scss\.d\.ts$/,
/less\.d\.ts$/,
]),
2、使用动态html模板
const HtmlWebpackPlugin = require("html-webpack-plugin"); // "html-webpack-plugin": "^4.3.0"
new HtmlWebpackPlugin({
filename: 'index.html',
title: 'app',
template: path.resolve(__dirname, 'public/index.html')
}),
- template: 如果路径错误,页面将展示项目文件列表,也就是找不到入口html文件。
- title:
<title><%= htmlWebpackPlugin.options.title %></title>,html中的标题
3、设置常用全局依赖变量($,_,lodash,React等等)
- 添加配置
new webpack.ProvidePlugin({
_: 'lodash',
moment: 'moment',
})
- 声明类型global.d.ts
declare global {
const _: typeof lodash;
}
- 不建议使用,经测试打包后文件体积变大,丢失了import按需加载
4、使用css压缩
- 插件配置
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "css/[name].[hash:8].css"
}),
- rules解析配置,当打包时使用压缩,当开发编译时使用style-loader生成style放入head标签中(有利于热更新)。
{
test: /\.(c|sc|sa)ss$/,
include: path.resolve(__dirname, './src'), // 提升d.ts的索引速度
use: [
process.env.BABEL_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
...
]
}
5、配置动态文件输出地址(完整拼接文件前缀,非'/'相对路径)
- 配置 创建独立文件 appPublicPath.js
__webpack_public_path__ = window.ENV.publicPath;
- 入口index.js文件中引入
import './appPublicPath.js';
- 主要用于方便部署,代替了webpack中output.publicPath静态属性,如果设置所有文件的引入前面自动拼接 window.ENV.publicPath完整。
6、编译和打包进程进度状态bar显示
- 插件一:webpackbar
const WebpackBar = require('webpackbar');
// 配置plugins: []
new WebpackBar()
- 插件二:progress-bar-webpack-plugin
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
// 配置
new ProgressBarPlugin({
format: 'start[:bar]' + chalk.green.bold(':percent') + ' (:elapsed seconds)',
clear: false
}),
7、打包时将静态资源移动到指定文件夹下
- 将public中的ENV文件移到打包后的文件夹中
const CopyWebpackPlugin = require('copy-webpack-plugin');
new CopyWebpackPlugin({
patterns: [
path.join(__dirname, 'public/ENV.js'),
]
}),
8、设置输出js文件的hash命名
output: {
publicPath: "/",
filename: "js/[name].js", // 主输出文件不加hash
chunkFilename: 'js/[name].[hash:8].js', // 所有按需加载文件使用hash命名
path: path.resolve(__dirname, "dist"), // 打包到指定目录
},
9、设置输出css文件的hash命名,(压缩模式下)
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "css/[name].[hash:8].css"
}),
10、模块解析:引入文件时可以文件名可以不带后缀
resolve: {
extensions: [".tsx", ".ts", ".js", 'jsx'], // 引入该后缀时可以文件名可以不带后缀
},
11、配置便捷路径
resolve: {
alias: {
'@': path.resolve(__dirname, './src/'),
'components': path.resolve(__dirname, './src/components'),
}
},
- TS模块下还需要同时设置tsConfig
"compilerOptions": {
"baseUrl": "./", //解析非相对模块的基准目录
"paths": {
"@/*": ["src/*"], //路径映射,如在文件中使用‘@/’相当于‘src/’
"components/*": ["src/components/*"]
},
}
12、设置默认导出
// 想要结果
import React from "react";
// 而不是
import * as React from "react";
// -----tsConfig.compilerOptions配置-------
// 允许从没有设置默认导出的模块中默认导入。不影响代码的输出,仅为了类型检查。
"allowSyntheticDefaultImports": true
13、指定打包或编译后的分包文件名称
// 添加 /*webpackChunkName: 'home'*/ 不可中文
{
title: '主页',
component: import(/*webpackChunkName: 'home'*/'../pages/Home/index'),
path: '/'
}
###打包后的结果
14、ts环境如何import引入多媒体资源,png、jpg、svg...
- 在TS中所有引入的文件都需要文件类型声明,在typscript中是无法识别非代码资源的,所以会报错TS2307: cannot find module '.png'。因此,我们需要主动的去声明这个module。
// tsconfig.json
//编译包含在src及其子目录下的所有匹配的文件
"include": ["src/**/*", "./global.d.ts", "./types/**/*"],
- global.d.ts 全局声明文件
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
15、添加webpack编译热更新功能
- 安装yarn add react-hot-loader webpack-dev-server --dev
- 在babel.config.js中添加配置
plugins:[
'react-hot-loader/babel', // 放在第一个
....
]
- 应用入口index.tsx文件
import {hot} from 'react-hot-loader';
export default hot(module)(App);
- script启动命令添加--hot
"dev": "BABEL_ENV=development webpack-dev-server --open --watch --hot",
16、webpack启动命令:指定配置js文件
### package.json -> webpack指令后添加--config
--config webpack.config.js
"build": "webpack --config webpack.config.js" // 指定根目录下的js文件
17、启动命令:指定开发模式启动
- 方法一: BABEL_ENV=development 使用进程
"dev": "BABEL_ENV=development webpack-dev-server --open",
// 通过process.env.BABEL_ENV === 'development' 在commonjs模块文件中调用
- 方法二:从 CLI 参数中传递
生产build webpack --mode=production
开发dev webpack-dev-server --mode=development
18、分割webpack配置
// 增量合并,不覆盖(其他合并方式暂不整理)
const webpackMerge = require('webpack-merge');
module.exports = webpackMerge([config1,config2,config3,...]);
19、性能优化--减小lodash体积
- 安装 @babel/preset-env babel-plugin-lodash 依赖
- 可以使用babel-loader在对*.js文件进行解析,然后借助于babel-plugin-lodash插件对引用的lodash进行类似tree shaking的操作,这样就可以去除未使用的lodash代码片段。
- rules配置
{
test: /\.(js|ts)x?$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'], // 预加载环境配置
plugins: ['lodash']
}
},
{
loader: 'ts-loader'
},
]
},
- 深度优化,进一步压缩,安装lodash-webpack-plugin
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
// plugins插件配置
plugins: [
new LodashModuleReplacementPlugin,
]
20、性能分析--性能分析插件
提供在webpack构建中所需的所有相关信息,无论是dev还是prod,许多功能都在路线图上。
- 插件webpack-jarvis
const Jarvis = require("webpack-jarvis");
new Jarvis({
port: 1337 // 访问端口号 http://localhost:1337
})
- 插件webpack-bundle-analyzer
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: 'localhost',
analyzerPort: 8889,
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
})
21、Antdesign 4安装和按需加载优化配置
1、安装依赖
"babel-plugin-import": "^1.13.0", //dev
"@types/antd": "^1.0.0", //dev
"antd": "^4.3.4",
2、添加规则
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
'lodash',
['import', {libraryName: 'antd', libraryDirectory: 'lib', style: true}]
]
}
}
- 设置 style:true 相当于引入 @import '~antd/dist/antd.less';
22、性能优化-减少编译体积大小-减小moment体积
- 如果项目中使用了国际化
// 性能优化-处理moment的local国际化--本地资源的重定向
new webpack.ContextReplacementPugin(
/moment[\/\\]locale$/, //匹配文件夹
/zh-cn|en-us/ // 中英文语言包
)
- 如果没有使用国际包
//性能优化-处理moment的local国际化--本地资源的重定向
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
23、构建优化-将大型库外链 && 将库预先编译
- 拆分bundles(主要解决打包速度问题,但会造成首页加载变慢)。 针对库预先编译,webpack也提供了相应的插件,那就是webpack.Dllplugin,这个插件可以预先编译制定好的库,最后在实际项目中使用webpack.DllReferencePlugin将预先编译好的库关联到当前的编译结果中,无需重新编译。
- 不建议,或造成首页加载文件体积变大。webpack4优化已经很好了,4版本之前可能需要这么优化。
24、构建优化-使用缓存提高编译速度和打包速度
- 安装 uglifyjs-webpack-plugin
- 添加配置
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true, //是否启用文件缓存,默认缓存在node_modules/.cache/uglifyjs-webpack-plugin.目录
parallel: true, //使用多进程并行运行来提高构建速度(默认cpu-1个数进行多进程加速)
sourceMap: true // 对cheap-source-map无效
}),
],
},
}
25、构建优化-使用缓存插件极大提升编译和打包速度
- 原理: HardSourceWebpackPlugin是webpack的插件,为模块提供中间缓存步骤。为了查看结果,您需要使用此插件运行webpack两次:第一次构建将花费正常的时间。第二次构建将显着加快(大概提升90%的构建速度[据说如此!!!,小项目demo测试提升10.2秒到7.1秒,打包后2.2M,大项目未测试])。
- 使用:
cnpm install --save-dev hard-source-webpack-plugin
// 或yarn安装
yarn add --dev hard-source-webpack-plugin。
// 在webpack的插件配置中添加此插件。
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
new HardSourceWebpackPlugin()
#---第二次打包效果,从缓存总获取
[hardsource:807490d0] Using 73 MB of disk space.
[hardsource:807490d0] Tracking node dependencies with: yarn.lock.
[hardsource:807490d0] Reading from cache 807490d0...
#---配置发生修改时重新建立缓存
[hardsource:fa396c04] Using 168 MB of disk space.
[hardsource:fa396c04] Writing new cache fa396c04...
[hardsource:fa396c04] Tracking node dependencies with: yarn.lock.
26、构建优化-并行打包
- 并行化构建对于 webpack 2/3 的性能有明显的提升,使用 webpack4+时,速度提升的收益似乎要少得多。
- 并行化构建有两种方式: happypack 和 thread-loader。(happypack官方已不再维护!!!)
- 测试thread-loader
const threadLoader = require('thread-loader');// 多进程打包
const jsWorkerPool = {
// 闲置时定时删除 worker 进程 默认为 500ms
// 可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在
poolTimeout: 2000
};
// 进程预热warmup,防止进程延迟
threadLoader.warmup(jsWorkerPool, ['babel-loader']);
#---rules配置
{
test: /\.(js|ts|jsx|tsx)?$/,
exclude: /(node_modules)/,
use: [
{
loader: 'thread-loader',
options: jsWorkerPool
},
'babel-loader'
]
},
27、构建优化-externals-将公共依提取出来不打包,通过script加载
- webpack打包优化之外部扩展externals的实际应用目录
# webpack配置
externals: { vue : 'Vue', "echarts": 'echarts', "element-ui": 'ELEMENT' }
# // 在模板文件index.html中,添加<script>标签
...
<script src="echarts.js"></script>
...