下载资源文件、相关配置

基础配置

将支持以下功能:

  • 分离开发环境、生产环境配置
  • 模块化开发
  • sourceMap 定位警告和错误
  • 动态生成引入 bundle.js 的 HTML5 文件
  • 实时编译
  • 封装编译、打包命令
  • 加载图片、字体、CSS、SCSS、PostCSS
  • React+TypeScript

1.新建项目

  1. mkdir REACT-CLI
  2. cd REACT-CLI
  3. // 初始化项目
  4. npm init -y
  5. mkdir src
  6. cd src
  7. code index.js

2.安装 webpack

  1. yarn add webpack webpack-cli -D

目录结构如下:

  1. - node_modules
  2. - src
  3. - index.js
  4. - package.json

3.新建 webpack 配置文件

  1. // 创建 config 目录
  2. mkdir config
  3. // 进入 config 目录
  4. cd ./config
  5. // Windows环境vscode创建通用环境配置文件
  6. code webpack.common.js
  7. // 创建开发环境配置文件
  8. code webpack.dev.js
  9. // 创建生产环境配置文件
  10. code webpack.prod.js

4.使用 webpack-marge 合并通用配置和特定环境配置

  1. yarn add webpack-merge -D

通用环境配置::

  1. // webpack.common.js
  2. module.exports = {};

开发环境配置:

  1. // webpack.dev.js
  2. const { merge } = require("webpack-merge");
  3. const common = require("./webpack.common");
  4. module.exports = merge(common, {}); // 暂不添加配置

生产环境配置:

  1. // webpack.prod.js
  2. const { merge } = require("webpack-merge");
  3. const common = require("./webpack.common");
  4. module.exports = merge(common, {}); // 暂不添加配置

项目结构如下:

  1. - config
  2. - webpack.common.js
  3. - webpack.dev.js
  4. - webpack.prod.js
  5. - node_modules
  6. - src
  7. - index.js
  8. - package.json

入口 entry

修改 webpack.commom.js:

  1. module.exports = {
  2. // 入口
  3. entry: {
  4. index: './src/index.js',
  5. },
  6. }

输出(output)

output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。
生产环境的 output 需要通过 contenthash 值来区分版本和变动,可达到清缓存的效果,而本地环境为了构建效率,则不引入contenthash。

config目录下新增 paths.js,封装路径方法:

  1. const fs = require('fs')
  2. const path = require('path')
  3. const appDirectory = fs.realpathSync(process.cwd());
  4. const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
  5. module.exports = {
  6. resolveApp,
  7. appPublic: resolveApp('public'),
  8. appHtml: resolveApp('public/index.html'),
  9. appSrc: resolveApp('src'),
  10. appDist: resolveApp('dist'),
  11. appTsConfig: resolveApp('tsconfig.json')
  12. }

修改开发环境配置文件 webpack.dev.js:

  1. const paths = require('./paths')
  2. module.exports = merge(common, {
  3. // 输出
  4. output: {
  5. // bundle 文件名称
  6. filename: '[name].bundle.js',
  7. // bundle 文件路径
  8. path: paths.appDist,
  9. // 编译前清除目录
  10. clean: true
  11. },
  12. })

修改生产环境配置文件 webpack.prod.js:

  1. const paths = require('./paths')
  2. module.exports = merge(common, {
  3. // 输出
  4. output: {
  5. // bundle 文件名称 【只有这里和开发环境不一样】
  6. filename: '[name].[contenthash].bundle.js',
  7. // bundle 文件路径
  8. path: paths.appDist,
  9. // 编译前清除目录
  10. clean: true
  11. },
  12. })
  • [name]- chunk name(例如 [name].js -> app.js)。如果 chunk 没有名称,则会使用其 id 作为名称
  • [contenthash] - 输出文件内容的 md4-hash(例如 [contenthash].js -> 4ea6ff1de66c537eb9b2.js

模式mode

通过 mode 配置选项,告知 webpack 使用相应模式的内置优化。

  • development

会将 DefinePluginprocess.env.NODE_ENV 的值设置为 development。为模块和 chunk 启用有效的名称。

  • production

会将 DefinePluginprocess.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginTerserPlugin

修改开发环境配置文件 webpack.dev.js:

  1. module.exports = merge(common, {
  2. // 开发模式
  3. mode: 'development',
  4. ...
  5. })

修改生产环境配置文件 webpack.prod.js:

  1. module.exports = merge(common, {
  2. // 生产模式
  3. mode: 'production',
  4. ...
  5. })

Source Map

开发时,webpack 将我们写的代码经过编译后,很难追踪到 error 和 warning 在源代码中的原始位置。source map可以将编译后的代码映射回原始源代码。

修改开发环境配置文件 webpack.dev.js:

  1. module.exports = merge(common, {
  2. // 开发工具,开启 source map,编译调试
  3. devtool: 'eval-cheap-module-source-map',
  4. })

source map 有许多 可用选项。本例选择的是 eval-cheap-module-source-map

完成上述配置后,可以通过 npx webpack --config config/webpack.prod.js打包编译

编译后,会生成这样的目录结构:

Webpack5配置 - 图1

webpack-dev-server

在每次编译代码时,手动运行npx webpack --config config/webpack.prod.js会显得很麻烦,webpack-dev-server 可以帮助我们在代码发生变化后自动编译代码。
安装:

  1. yarn add webpack-dev-server -D

修改开发环境配置文件 webpack.dev.js:

  1. module.exports = merge(common, {
  2. devServer: {
  3. // 告诉服务器从哪里提供内容,只有在你想要提供静态文件时才需要。
  4. static: './dist',
  5. },
  6. })

完成上述配置后,可以通过 npx webpack serve --open --config config/webpack.dev.js 实时编译。

HtmlWebpackPlugin

引入 HtmlWebpackPlugin 插件,生成一个 HTML5 文件,其中会引用打包生成的 bundle 文件。
安装:

  1. yarn add html-webpack-plugin -D

修改通用环境配置文件 webpack.commom.js:

  1. module.exports = {
  2. ...
  3. plugins: [
  4. // 生成html,自动引入所有bundle
  5. new HtmlWebpackPlugin({
  6. title: 'release_v0',
  7. }),
  8. ],
  9. }

重新 webpack 编译npx webpack --config config/webpack.prod.js,生成的目录结构如下

Webpack5配置 - 图2

新生成了 index.html,修改了title动态引入了 bundle.js 文件:

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>release_v0</title>
  6. <meta name="viewport" content="width=device-width,initial-scale=1">
  7. <script defer="defer" src="index.7d02a7c9bcd86981b6f4.bundle.js"></script>
  8. </head>
  9. <body>
  10. </body>
  11. </html>

优化执行命令

上述配置文件完成后,优化 webpack 的实时编译、打包编译指令。

通过 cross-env 配置环境变量,区分开发环境生产环境

安装:

  1. yarn add cross-env -D

修改 package.json:

  1. "scripts": {
  2. "dev": "cross-env NODE_ENV=development webpack serve --open --config config/webpack.dev.js",
  3. "build": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js"
  4. }

现在可以运行 webpack 指令:

  • npm run dev:本地构建
  • npm run build:生产打包

接下来继续完善配置,用 Webpack 搭建一个 SASS + TS + React 的项目,并且支持:

  • 加载图片
  • 加载字体
  • 加载 CSS
  • 使用 SASS
  • 使用 PostCSS,并自动为 CSS 规则添加前缀,解析最新的 CSS 语法,引入 css-modules 解决全局命名冲突问题
  • 使用 React
  • 使用 TypeScript

加载图片、字体

在 webpack 5 中,有内置的 Asset Modules,不必再引入file-loaderurl-loader处理文件了。

在实际开发过程中,推荐将大图片、字体文件压缩上传至 CDN,提高加载速度。

修改通用环境配置文件 webpack.commom.js:

  1. const paths = require('./paths');
  2. module.exports = {
  3. ...
  4. module: {
  5. rules: [
  6. {
  7. test: /\.(png|svg|jpg|jpeg|gif)$/i,
  8. include: paths.appSrc,
  9. type: 'asset/resource',
  10. },
  11. {
  12. test: /.(woff|woff2|eot|ttf|otf)$/i,
  13. include: [
  14. paths.appSrc,
  15. ],
  16. type: 'asset/resource',
  17. },
  18. ],
  19. },
  20. ...
  21. }

加载CSS相关

  • style-loader

style-loader 就是把 CSS 插入到 DOM 中,通过使用多个 <style></style> 自动把 styles 插入到 DOM 中.

  • css-loader

css-loader@importurl() 进行处理,就像 js 解析import/require()一样,让 CSS 也能模块化开发。

  • sass-loader

sass-loader 会加载sass/scss文件并且将他们编译成CSS

  • postcss-loader
    1.可以自动为 CSS 规则添加前缀
    2.将最新的 CSS 语法转换成大多数浏览器都能理解的语法
    3.css-modules 解决全局命名冲突问题

安装相关库和依赖:

  1. yarn add style-loader css-loader -D
  2. yarn add sass-loader sass -D
  3. yarn add postcss-loader postcss postcss-preset-env -D

修改通用环境配置文件 webpack.commom.js:

  1. module.exports = {
  2. ...
  3. module: {
  4. ...
  5. rules: [
  6. {
  7. test: /\.css$/,
  8. include: paths.appSrc,
  9. use: [
  10. // 将 JS 字符串生成为 style 节点
  11. "style-loader",
  12. // 将 CSS 转化成 CommonJS 模块
  13. "css-loader",
  14. ],
  15. },
  16. {
  17. test: /\.module\.(scss|sass)$/,
  18. include: paths.appSrc,
  19. use: [
  20. // 将 JS 字符串生成为 style 节点
  21. "style-loader",
  22. // 将 CSS 转化成 CommonJS 模块
  23. {
  24. loader: "css-loader",
  25. options: {
  26. // Enable CSS Modules features
  27. modules: true,
  28. importLoaders: 2,
  29. // 0 => no loaders (default);
  30. // 1 => postcss-loader;
  31. // 2 => postcss-loader, sass-loader
  32. },
  33. },
  34. // 将 PostCSS 编译成 CSS
  35. {
  36. loader: "postcss-loader",
  37. options: {
  38. postcssOptions: {
  39. plugins: [
  40. [
  41. // postcss-preset-env 包含 autoprefixer
  42. "postcss-preset-env",
  43. ],
  44. ],
  45. },
  46. },
  47. },
  48. // 将 Sass 编译成 CSS
  49. "sass-loader",
  50. ],
  51. },
  52. ]
  53. }
  54. ...
  55. }

JS相关

  1. yarn add babel-loader @babel/core @babel/preset-env -D
  • babel-loader 使用 Babel 加载 ES2015+ 代码并将其转换为 ES5
  • @babel/core Babel 编译的核心包
  • @babel/preset-env Babel 编译的预设,可以理解为 Babel 插件的超集

使用 React + TypeScript

  1. yarn add react react-dom @types/react @types/react-dom -D
  2. yarn add typescript esbuild-loader -D
  3. //为提高性能,摒弃了传统的 ts-loader,选择最新的 esbuild-loader。

修改通用环境配置文件 webpack.commom.js:

  1. module.exports = {
  2. resolve: {
  3. extensions: ['.tsx', '.ts', '.js'],
  4. },
  5. module: {
  6. rules: [
  7. {
  8. test: /\.(js|ts|jsx|tsx)$/,
  9. include: paths.appSrc,
  10. use: [
  11. {
  12. loader: 'esbuild-loader',
  13. options: {
  14. loader: 'tsx',
  15. target: 'es2015',
  16. },
  17. }
  18. ]
  19. },
  20. ]
  21. }
  22. }

为兼容 TypeScript 文件,新增 typescript 配置文件 tsconfig.jsontsconfig相关提示

  1. {
  2. "compilerOptions": {
  3. "outDir": "./dist/",
  4. "noImplicitAny": true,
  5. "module": "es6",
  6. "target": "es5",
  7. "strict": true,//通过启用TypeScript的strict编译器选项,编译器将在最严格的模式下运行,在运行之前捕获更多类型问题。
  8. "jsx": "react",
  9. "allowJs": true,
  10. "moduleResolution": "node",
  11. "allowSyntheticDefaultImports": true,
  12. "esModuleInterop": true,
  13. "forceConsistentCasingInFileNames": true,//强制统一不同操作系统的文件名
  14. "importHelpers": true,//通过启用TypeScript的importlpers编译器选项,编译器将使用tslib包,并减少输出的大小
  15. }
  16. }