4

从零开始搭建react基础开发环境(基于webpack5) - handsomezyw

 1 year ago
source link: https://www.cnblogs.com/handsomezyw/p/16633087.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近利用闲暇时间把webpack系统的学习了下,搭建出一个react环境的脚手架,写篇文章总结一下,帮助正在学习webpack小伙伴们,如有写的不对的地方或还有可以优化的地方,望大佬们指出,及时改正。

git项目地址:https://github.com/handsomezyw/my-webpack

初始化项目

  1. 新建文件夹起名为my-webpack(文件夹名字任意取),然后初始化项目,使用如下指令,会在你的项目根目录生成package.json文件,-y 参数是省去填写初始化的package.json信息。
npm init -y

接着安装webpack、webpack-cli、webpack-dev-server

npm install webpack webpack-cli webpack-dev-server --save-dev
  1. 创建src文件夹存放代码等文件,在src文件夹下创建webpack入口文件app.tsx
  2. 创建config文件夹用来保存我们的webpack配置文件,方便扩展管理,使用webpack-merge库将我们写的配置文件组合起来(记得用npm安装webpack-merge)。
  • 创建基础配置文件 webpack.base.js
  • 创建开发环境配置文件 webpack.dev.js
  • 创建生产环境配置文件 webpack.prod.js
image.png

配置文件编写

webpack.base.js文件(基础配置)

const path = require("path");

// 当前项目工作目录根路径
const RootProject = process.cwd();
// 根据参数获取需要的绝对路径
const getPath = (pathStr) => {
  return path.resolve(RootProject, `${pathStr}`);
};

module.exports = {
  // 入口文件路径
  entry:getPath("./src/app.tsx"), 
  // 使用插件
  plugins: [],
  module: {
    // 对模块(module)应用 loader
    rules: [],
  },
};

webpack.dev.js文件

const path = require("path");
// 合并文件配置
const { merge } = require("webpack-merge");
// 基础配置
const baseConfig = require("./webpack.base");
// 当前项目工作目录根路径
const RootProject = process.cwd();
// 根据参数获取需要的绝对路径
const getPath = (pathStr) => {
  return path.resolve(RootProject, `${pathStr}`);
};

// 开发环境配置
const devConfig = {
  // 开发模式
  mode: "development",
  // 只在发生错误时输出
  stats: "errors-only",
  // source map风格
  devtool: "inline-source-map",
  // webpack-dev-server 配置
  devServer: {
    // 从目录提供静态文件的选项(默认是 'public' 文件夹)
    static: getPath("./public"),
    // 启用 webpack 的 热模块替换 特性
    hot: true,
    // 当使用HTML5 History API时,index.html页面可能要代替404响应。
    // 解决了使用react-router-dom 使用 BrowserRouter 模式时,在
    // 浏览器输入路由地址是会请求接口报错的问题
    historyApiFallback: true, 
  },
};

module.exports = merge(baseConfig, devConfig);

webpack.prod.js文件

const path = require("path");
// 合并文件配置
const { merge } = require("webpack-merge");
// 基础配置
const baseConfig = require("./webpack.base");
// 当前项目工作目录根路径
const RootProject = process.cwd();
// 根据参数获取需要的绝对路径
const getPath = (pathStr) => {
  return path.resolve(RootProject, `${pathStr}`);
};

// 生产环境配置
const prodConfig = {  
  // 生产模式
  mode: "production",
  // 打包输出配置
  output: {
    // 打包输出路径
    path: getPath("./dist"),
    // 打包输出文件名
    filename: "[name]_[chunkhash:8].js",
    // 开启打包清理文件夹功能
    clean: true,
  },
  // 使用插件
  plugins: [],
};

module.exports = merge(baseConfig, prodConfig);

接着我们在package.json文件添加运行指令

image.png

--config参数是指定运行使用的配置文件路径

当我们在命令行使用npm run start命令的时候就会运行webpack-dev-server开启 web server服务,并具有实时重新加载的功能,当我们修改文件时,不需要手动刷新浏览器,就能看到修改后的效果。

当我们在命令行使用npm run start命令的时候就会运行webpack构建打包我们的项目

至此webpack的基础配置结构就写好了,接下来就是开始完善配置文件功能。

使用html-webpack-plugin

这个插件可以帮我们生成一个html文件,在 body 中使用 script 标签引入你所有 webpack 生成的 bundle,也即是我们output输出的文件。这样就不需要每次手动创建一个html文件,在手动引入我们打包好的js文件。
安装依赖

npm install --save-dev html-webpack-plugin

在我们的webpack.base.js加入使用

// webpack.base.js
// 生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
    new HtmlWebpackPlugin({
      // 模版文件
      template: getPath("./public/index.html"),
      filename: "index.html",
      inject: true,
      minify: {
        html5: true, // 根据HTML5规范解析输入
        collapseWhitespace: true, // 折叠构成文档树中文本节点的空白
        preserveLineBreaks: false, // 当标签之间的空格包含换行符时,总是折叠为1个换行符(永远不要完全删除它)。必须与collapseWhitespace=true一起使用
        minifyCSS: true, // 在样式元素和样式属性中缩小CSS(使用clean-css)
        minifyJS: true, // 在脚本元素和事件属性中最小化JavaScript(使用Terser)
        removeComments: false, // 带HTML注释
      },
    }),
}

解析jsx语法

  • 将es2015+的语法代码转换为向后兼容的 JavaScript 语法
  • 解析jsx语法

为了提升webpack构建速度,我们可以在使用loader的时候限定解析的范围,使用include,这里需要注意的是,
一般设置src,但是有时node_modules的第三方依赖打包好的库,可能含有es6的语法,为了更好的兼容性,我们可以把第三方的依赖库通过include加入到解析名单,比如:include:["./src","./node_modules/react-router-dom"],不过觉得麻烦的话,又不在意构建速度的话,可以不限定解析范围。

这里我们使用babel-loader来帮助我们解析jsx和es2015以后的版本语法。

使用core-js给我们新的js api打补丁(polyfill)。

关于babel可前往babel官网查看更多配置用法。

安装所需依赖

npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react core-js

接着在webpack.base.js文件中添加babel-loader解析js,jsx文件

// webpack.base.js
//...
 module: {
    // 对模块(module)应用 loader
    rules: [
      {
        test: /\.jsx?$/,
        // include限定解析范围
        include: getPath("./src"),
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: [
                [
                   // 解析js预设
                  "@babel/preset-env",
                  {
                    // 自动打补丁
                    useBuiltIns: "usage",
                    // 指定core-js版本
                    corejs: { version: "3.24.1", proposals: true },
                  },
                ],
                // 解析jsx预设
                "@babel/preset-react",
              ],
              plugins: [],
            },
          },
        ],
      },
    ],
  },
//...

解析css、less文件

  • 解析css、less
  • 提取css成单独文件
  • css浏览器前缀补齐
  • 开启css modules
  • 引入全局less变量

安装所需依赖

npm install --save-dev css-loader less less-loader mini-css-extract-plugin postcss-loader postcss style-resources-loader

这里需要注意的是css前缀补齐,还需要在package.json文件添加browserlist属性指定版本,不然css补齐前缀不生效。

image.png
//webpack.base.js
// 将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
//...
plugins: [
    new MiniCssExtractPlugin({
      // 提取css文件 文件名
      filename: "[name]_[contenthash:8].css",
    }),
]
 module: {
    // 对模块(module)应用 loader
    rules: [
       {
        test: /\.css$/,
        use: [
          // "style-loader",
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              modules: {
                auto: true,
                localIdentName: "[path][name]__[local]--[hash:base64:5]",
              },
              importLoaders: 1,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: ["postcss-preset-env"],
              },
            },
          },
        ],
      },
      {
        test: /\.less$/,
        use: [
          // "style-loader", //将style插入到head中
          MiniCssExtractPlugin.loader, // 提取css成单独文件
          {
            loader: "css-loader",
            options: {
              modules: {
                auto: true, // 允许根据文件名中含有module的文件开启css modules
                localIdentName: "[path][name]__[local]--[hash:base64:5]", // 允许配置生成的本地标识符(ident)
              },
              // css-loader之前加载多少个loader
              importLoaders: 3,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                // 包含添加css前缀的预设
                plugins: ["postcss-preset-env"],
              },
            },
          },
          {
            loader: "less-loader",
            options: {
              // 生成source map
              sourceMap: true,
            },
          },
          {
            // 将定义全局的less变量注入到其他样式文件,无须手动引入
            loader: "style-resources-loader",
            options: {
              patterns: [getPath("./src/global.less")],
            },
          },
        ],
      },
    ],
  },
//...

解析图片资源

// webpack.base.js
//...
module:{
    rules: [
      {
        test: /\.(png|jpg|gif|jpeg)$/,
        type: "asset/resource",
      },
    ]
}
//...

解析字体资源

// webpack.base.js
//...
module:{
    rules: [
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        type: "asset/resource",
      },
    ]
}
//...

解析ts、tsx

安装所需依赖

npm install --save-dev typescript ts-loader fork-ts-checker-webpack-plugin

安装完依赖后,初始化ts生成ts配置文件tsconfig.json,使用如下指令(确保当前命令行所处位置为项目根目录):

 node_modules/.bin/tsc --init
image.png

修改tsconfig.json文件的配置(关于配置可前往ts官网查询)

{
    "compilerOptions": {
        "target": "ES5",
        "module": "ES6",
        "jsx": "react",
        "paths": {
          "@/*": ["./src/*"]
        },
        "sourceMap": true,
    }
}
// webpack.base.js
// 在一个独立进程上运行TypeScript类型检查器的Webpack插件。
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
//...
plugins: [
    new ForkTsCheckerWebpackPlugin()
],
module:{
    rules: [
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        include: getPath("./src"),
      },
    ]
}
//...

命令行显示的信息优化

通常我们运行项目时都会显示很多构建信息

image.png

每次重新编译都会有一大堆信息,显然不利于我们专注研发,为此我们可以通过stats设置显示信息的风格。

在使用一个插件优化显示命令行显示。

npm install --save-dev @soda/friendly-errors-webpack-plugin
// webpack.base.js
// 命令行提示优化插件
const FriendlyErrorsWebpackPlugin = require("@soda/friendly-errors-webpack-plugin");
module.exports = {
// ...
// 只在发生错误时输出
stats: "errors-only",
plugins: [new FriendlyErrorsWebpackPlugin()]
// ...
}
image.png

eslint prettier配置

使用eslint和prettier帮助我们检查代码格式是否正确和统一代码格式。

vscode安装ESLint、Prettier插件。

这里我们使用airbnb公司的eslint基础规则。

先安装依赖

npm install --save-dev eslint-config-airbnb eslint eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y

然后在创建.eslintrc.js文件,配置我们的eslint规则。配置选项可前往eslint官网查看。

module.exports = {
  env: {
    node: true, // 启用node中全局变量
    browser: true, // 启用浏览器中全局变量
  },
  // extends: "eslint:recommended",
  extends: ["airbnb", "airbnb/hooks", "plugin:prettier/recommended", "prettier"],

  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: "latest",
    sourceType: "module",
  },
  settings: {
    "import/resolver": {
      webpack: {
        config: "./config/webpack.base.js",
      },
    },
  },
  rules: {
    // "off" or 0 - 关闭规则
    // "warn" or 1 - 将规则视为一个警告(不会影响退出码)
    // "error" or 2 - 将规则视为一个错误 (退出码为1)

    // 要求或禁止在类成员之间出现空行
    "lines-between-class-members": [0, "always"],
    // 允许的扩展集是可配置的 jsx可以出现在js中
    "react/jsx-filename-extension": [
      1,
      {
        extensions: [".js", ".jsx"],
      },
    ],
    // 函数组件声明方式
    "react/function-component-definition": [
      2,
      {
        namedComponents: ["function-declaration", "function-expression", "arrow-function"],
        unnamedComponents: ["function-expression", "arrow-function"],
      },
    ],
    // 禁用 console
    "no-console": "off",
    // 要求 require() 出现在顶层模块作用域中
    "global-require": "off",
    "import/no-extraneous-dependencies": "off",
  },
};

接着安装eslint-webpack-plugin插件,该插件使用 eslint 来查找和修复 JavaScript 代码中的问题。

npm install eslint-webpack-plugin --save-dev

接着在我们webpack配置文件中使用eslint-webpack-plugin插件

// webpack.base.js
const path = require("path");
// 使用 eslint 来查找和修复 JavaScript 代码中的问题
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
// 当前项目工作目录根路径
const RootProject = process.cwd();
// 根据参数获取需要的绝对路径
const getPath = (pathStr) => {
  return path.resolve(RootProject, `${pathStr}`);
};
module.exports = {
    plugins: [
         new ESLintWebpackPlugin({
          // 指定检查文件的根目录
          context: getPath("./src"),
        }),
    ]
}

eslint配置完后,在创建.prettierrc.js文件配置Prettier。配置选项可前往Prettier官网查看。

module.exports = {
  // 一行最多 100 字符
  printWidth: 100,
  // 关闭 tab 缩进
  useTabs: false,
  // 使用 2个tab 缩进
  tabWidth: 2,
  // 行尾需要有分号
  semi: true,
  // 使用单引号
  singleQuote: false,
  // 对象key是否使用引号 
  // as-needed 仅在需要的时候使用
  // consistent 有一个属性需要引号,就都需要引号
  // preserve 保留用户输入的情况
  quoteProps: "as-needed",
  // jsx 使用单引号代替双引号
  jsxSingleQuote: false,
  // 末尾不需要逗号 
  trailingComma: "all",
  // 大括号内的首尾需要空格
  bracketSpacing: true,
  // jsx 标签的反尖括号需要换行
  jsxBracketSameLine: false,
  // 箭头函数,只有一个参数的时候,也需要括号 <always|avoid>
  arrowParens: "always",
};

需要注意的是ESLint和Prettier配置可能会产生冲突,这时我们可以安装eslint-config-prettier插件和eslint-plugin-prettier插件,来解决冲突。

eslint-config-prettier插件 关闭所有可能与Prettier冲突的ESlint规则 使用要在eslint配置文件的extends数组最后加"prettier"

eslint-plugin-prettier插件 将Prettier作为ESLint的规则来使用,相当于代码不符合Prettier的规范时,会有提示信息 使用要在eslint配置文件的extends数组加入"plugin:prettier/recommended"

npm install --save-dev eslint-config-prettier eslint-plugin-prettier prettier

这样配置就完成了,如果有什么需要修改的规则可在.eslintrc.js文件中修改rules来修改elslint规则。

我们可以写一些单元测试检测我们脚手架基础功能是否有问题,比如是否生成js文件,css文件,index.html。

这里我们使用mocha测试框架来编写我们的测试用例。

npm install --save-dev mocha

接着在我们项目下创建test文件夹

image.png

接着在test文件夹下创建index.js文件编写测试用例。

// index.js
// 这里我们使用了glob-all库来判断是否有文件(记得安装这个库)
const glob = require("glob-all");

describe("检查是否生成了html文件", () => {
  it("生成html文件", (done) => {
    const files = glob.sync(["./dist/index.html"]);

    if (files.length > 0) {
      done();
    } else {
      throw new Error("生成html文件失败");
    }
  });
});

然后在package.json文件加入运行测试指令

image.png

先运行指令npm run build指令打包,成功后在运行npm run test指令

image.png

这样一个简单的测试用例就完成了。

接下来就是查看测试覆盖率,可以使用nyc这个库,有兴趣可以去看看。

构建速度优化

随着项目文件的增多,webpack打包和运行项目的速度必然会下降,我们可以优化一下。

限定解析范围(include,exclude)

我们可以在使用loader的时候,使用include,exclude去控制解析文件的范围,比如只解析src文件夹下的文件include: ["./src"]。

开启多进程构建

使用 thread-loader 来开启多进程构建,提升我们的构建速度。

npm install --save-dev thread-loader

然后在我们使用的loader前面加入(也就是放在use数组第一位),因为loader的解析是从右往左解析的,所以放在第一个。

需要注意的是ts-loader配合thread-loader,我们得多一点额外的设置

// 在一个独立进程上运行TypeScript类型检查器的Webpack插件。
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");

module.exports = {
    plugins: [
            new ForkTsCheckerWebpackPlugin({
              typescript: {
                diagnosticOptions: {
                  semantic: true,
                  syntactic: true,
                },
          },
        })
    ],
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: [
                    {
                        loader: "ts-loader",
                        options: {
                          happyPackMode: true,
                        },
                    }
                ]
            }
        ]
    }
}
// webpack官网thread-loader的例子
use: [
  {
    loader: "thread-loader",
    // 有同样配置的 loader 会共享一个 worker 池
    options: {
      // 产生的 worker 的数量,默认是 (cpu 核心数 - 1),或者,
      // 在 require('os').cpus() 是 undefined 时回退至 1
      workers: 2,

      // 一个 worker 进程中并行执行工作的数量
      // 默认为 20
      workerParallelJobs: 50,

      // 额外的 node.js 参数
      workerNodeArgs: ['--max-old-space-size=1024'],

      // 允许重新生成一个僵死的 work 池
      // 这个过程会降低整体编译速度
      // 并且开发环境应该设置为 false
      poolRespawn: false,

      // 闲置时定时删除 worker 进程
      // 默认为 500(ms)
      // 可以设置为无穷大,这样在监视模式(--watch)下可以保持 worker 持续存在
      poolTimeout: 2000,

      // 池分配给 worker 的工作数量
      // 默认为 200
      // 降低这个数值会降低总体的效率,但是会提升工作分布更均一
      poolParallelJobs: 50,

      // 池的名称
      // 可以修改名称来创建其余选项都一样的池
      name: "my-pool"
    },
  },
  // 耗时的 loader(例如 babel-loader)
];

开启多进程压缩

webpack5默认是使用TerserWebpackPlugin插件来压缩js,可使用多进程并发运行以提高构建速度。
把下面的配置加入到我们的webpack.prod.js配置文件中,开启多进程并发运行压缩。

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        // 开启多进程并发运行
        parallel: true,
      }),
    ],
  },
};

预编译资源

预编译资源就是我们可以把不需要经常变动的第三方依赖,如react,react-dom等,提前打包好,在webpack构建时不用在去编译已经编译好的依赖了,这样就可以大幅提升构建速度。

在webpack中,我们使用DllPlugin 和 DllReferencePlugin这两个webpack自带的插件,帮助我们完成资源预编译。

首先在我们的config文件夹下创建webpack.dll.js,写入如下代码

const path = require("path");
const webpack = require("webpack");

// 当前项目工作目录路径
const RootProject = process.cwd();

module.exports = {
  entry: {
    // 根据你的需要添加,这里是把react,react-dom预编译
    library: ["react", "react-dom"],
  },
  output: {
    filename: "[name].dll.js",
    path: path.resolve(RootProject, "./library"),
    library: "[name]_[hash]",
  },
  plugins: [
    new webpack.DllPlugin({
      // 与output.library保持一致
      name: "[name]_[hash]",
      path: path.resolve(RootProject, "./library/[name]-manifest.json"),
    }),
  ],
};

然后在package.json加入运行构建指令

image.png

然后我们预编译资源的配置就写好了,接着安装react,react-dom,

npm install react react-dom 

接着在命令行运行npm run dll指令生成预编译资源资源

image.png

可以看到成功生成了library文件夹及文件夹下的预编译资源library.dll.js,文件夹中json文件是给DllReferencePlugin使用告诉webpack哪些是编译好的资源,不用在编译了。

最后在我们的webpack.prod.js文件中使用DllReferencePlugin。还有帮我们把预编译资源引入到项目中的插件add-asset-html-webpack-plugin(其实就是把我们生成的预编译文件复制一份到webpack的ouput输出目录,并把它通过script标签引入到output输出目录下的index.html文件中)

npm install --save-dev add-asset-html-webpack-plugin
// webpack.prod.js
const webpack = require("webpack");
// 将指定js文件提取至压缩目录,并用script标签引入
const AddAssetHtmlPlugin = require("add-asset-html-webpack-plugin");

module.exports = {
    plugins: [
        new webpack.DllReferencePlugin({
          // 编译时用于加载 JSON manifest 的绝对路径
          manifest: require(getPath("./library/library-manifest.json")),
        }),
        new AddAssetHtmlPlugin({
          filepath: getPath("./library/library.dll.js"),
          publicPath: "./",
        }),
    ]
}

这样就完成了预解析资源。

构建体积优化

随着项目文件的增多,打包出来bundle体积会越来越大,我们可以做些优化。

使用cdn引入第三方库

防止将某些import的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖。
比如下面的例子,lodash不会被打包到项目中,而是通过cdn的形式引入。

// 官方文档例子
module.exports = {
  // ...
  externalsType: 'script',
  externals: {
    lodash: ['https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js', '_'],
  },
};

// 使用
import _ from 'lodash';
console.log(_.head([1, 2, 3]));

包体积分析,针对优化

我们可以使用webpack-bundle-analyzer插件,分析打包好的文件大小,便于我们分析优化哪个文件过大,针对的去做一些优化。

npm install --save-dev webpack-bundle-analyzer
// webpack.prod.js
// 分析构建体积插件
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");

module.exports = {
    plugins: [
        new BundleAnalyzerPlugin()
    ]
}

运行完构建效果如下

image.png

图片压缩我们可以使用image-minimizer-webpack-plugin插件(下载可能有点慢,多下几次),这里我们使用无损压缩。

npm install --save-dev image-minimizer-webpack-plugin imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo
// webpack.prod.js
// 图片压缩插件(使用无损压缩配置)
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
module.exports = {
    new ImageMinimizerPlugin({
      minimizer: {
        // implementation: ImageMinimizerPlugin.imageminMinify,
        implementation: ImageMinimizerPlugin.imageminGenerate,
        options: {
          // Lossless optimization with custom option
          // Feel free to experiment with options for better result for you
          plugins: [
            ["gifsicle", { interlaced: true }],
            ["jpegtran", { progressive: true }],
            ["optipng", { optimizationLevel: 5 }],
            // Svgo configuration here https://github.com/svg/svgo#configuration
            [
              "svgo",
              {
                plugins: [
                  {
                    name: "preset-default",
                    params: {
                      overrides: {
                        // customize default plugin options
                        inlineStyles: {
                          onlyMatchedOnce: false,
                        },
                        // or disable plugins
                        removeDoctype: false,
                      },
                    },
                  },
                ],
              },
            ],
          ],
        },
      },
    }),
}

css压缩

我们可以使用css-minimizer-webpack-plugin这个插件来帮我们压缩css文件。

需要注意的是,使用这个插件会导致terser-webpack-plugin插件压缩js失效,解决办法是再次引入terser-webpack-plugin

npm install --save-dev css-minimizer-webpack-plugin
// webpack.prod.js
// 这个插件使用 cssnano 优化和压缩 CSS。
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 压缩js插件
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
    optimization: {
        minimize: true,
        minimizer: [
          new CssMinimizerPlugin(),
          new TerserPlugin({
            parallel: 4
          }),
        ],
    }
}

SplitChunksPlugin

我们可以通过SplitChunksPlugin来抽取公共资源包,如lodash等,达到减小打包的体积。
使用如下配置,当我们项目中引用到了lodash库的时候,lodash会被单独抽取出来,在名为vendor开头的js文件中。

module.exports = {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/](lodash)[\\/]/,
          name: "vendor",
          chunks: "all",
        },
      },
    },
  },
}
image.png

关于自动部署

之前买了个腾讯云的服务器,最近打算写写express练练手,但是发现个问题,我打包好的文件怎么弄到服务器上去,然后就去百度了解了下ssh传输文件,前提是你的服务器要安装openssh-server,可以百度一下安装方法,安装好了后,就可以使用sftp(安全文件传输)通过登录密码验证的形式连接你的服务器传输文件。也可以配置密钥连接省去每次输入密码。但是还是有个问题,服务器端我用pm2管理我的项目文件夹,只要每次把新的打包文件重新拷贝一份到服务器端的项目文件夹下,就可以完成项目更新,这导致服务器端的项目更新每次都得通过ssh去把文件传上去,这样才能完成服务器端的项目文件更新,感觉有点麻烦,如果能执行完npm run build后自动把我的文件传到服务端该多省事呀,基于这个想法,查了查文档写了个自动部署的插件@handsomezyw/auto-deploy-webpack-plugin完成这件事。

先安装插件

npm install --save-dev @handsomezyw/auto-deploy-webpack-plugin

使用方法也很简单

// webpack.prod.js
// 自动部署到服务端插件
const AutoDeployWebpackPlugin = require("@handsomezyw/auto-deploy-webpack-plugin");

module.exports = {
    plugins: [
        new AutoDeployWebpackPlugin({
          // 服务器配置
          serverOptions: {
            // 服务器用户名
            username: "administrator",
            // 服务器ip地址
            host: "xxx.xx.x.xxx",
            // 服务器登录密码
            password: "123456",
          },
          // 本地要上传到服务端的文件夹路径
          localPath: "/Users/zengyongwen/Desktop/study/webpack-study/dist",
          // 上传到服务器文件夹路径(这里需要注意的是,会把该文件夹先清理一遍,再上传)
          serverPath: "Desktop/my-system/public",
        }),
    ]
}

最后我们在安装下react、react-dom的声明文件

npm install --save-dev @types/react @types/react-dom

至此一个基础的react环境就搭建成功了。

学习webpack的时候,我也是云里雾里,一开始就对着官方文档看,越看越头大,于是就去找一些关于webpack的文章和视频学习,发现好多都是webpack4的,于是我就对着官方文档的例子改改,找一些webpack5的实现方案等,多动手实践,慢慢的就对webpack的配置有了一点点了解,总的来说,搭建出一个自己的脚手架,还是有点成就感,哈哈。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK