TS项目构建(一):webpack初篇

1,257 阅读2分钟
  • 从零构建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>
...