消除无用代码!让前端代码根据环境巧妙加载的小技巧

前言

一般在项目开发中,代码部署都会有多种环境(比如测试环境、预发布环境、正式环境等),而一些代码需要根据环境不同来加载。举个实际例子,在项目的 index.html 中需要引入第三方的前端监控SDK。

<html>
  <head>
    <script src="https://cdn-go.cn/aegis/aegis-sdk/latest/aegis.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

以上的写法在多个环境中,SDK 都会进行日志上报,而在实际场景中往往只需要正式环境上报。虽然 SDK 可以配置上报域名,把其他环境的日志过滤掉。但这样就会有个不太优雅的点,既然其他环境不需要 SDK,为什么它还需要加载?能不能彻底让这段 script 消失掉?

本文就以该例子作为案例,分享在开发中如何工程化的根据环境去加载代码的解决方案。大概思路是通过获取构建时的命令行参数,结合 html-webpack-plugin 的模板语法对代码进行处理。

命令参数配置

注入环境参数

既然需要根据不同环境判断,那么就要在构建时为命令注入对应的环境参数。

package.json:

"scripts": {
    "build": "npm run build:prod",
    "build:dev": "node build/build.js --env dev",
    "build:test": "node build/build.js --env test",
    "build:preprod": "node build/build.js --env preprod",
    "build:prod": "node build/build.js --env prod"
}

这段 package.json 配置包含了一组用于构建项目的命令。每项对应着不同环境在构建时需要执行的命令,通过 --env 进行传参。

获取命令中的参数

接下来需要借助一个 npm 包帮助我们更便捷的获取参数。commander 是一个用于构建命令行界面(CLI)的 Node.js 模块。它提供了一种简单和灵活的方式来创建和管理命令行,使开发者能够轻松地定义命令、选项和参数。

安装它:

npm install commander -D

定义一个通用获取命令行参数的文件,命名为 program-argv.js

const { program } = require('commander')

program
  .option('-e --env [type]', 'environment type', 'prod')
  .parse(process.argv)

module.exports = program.opts()
  • option 方法对应的参数解释:

    • '-e --env [type]':这里指定了选项的短形式 -e 和长形式 –env,以及可选的参数 [type],表示环境类型。
    • 'environment type':这是选项的描述。
    • 'prod':这是选项的默认值,如果未提供环境类型参数,则默认为 prod。
  • parse 方法会让 commander 库解析传递给命令行参数(process.argv)。

  • opts 方法用于获取已解析的命令行选项的值。

下面我们就可以在 build 的时候引用该文件进行获取命令行参数:

const program = require('./program-argv.js')

console.log(program.env)

当我们使用 npm run build 的时候,上面 log 就会输出 prod。

html-webpack-plugin 配置

前置知识

以下是一段简单在 webpack 内配置 html-webpack-plugin 的例子,我们配置 template 对 index.html 进行处理,并传入 title 参数。

const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  entry: 'index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.js',
  },
  plugins: [new HtmlWebpackPlugin({
      filename: `index.html`,
      template: `./src/index.html`,
      title: '首页'
  })]
}

在 index.html 中可以使用 html-webpack-plugin 提供的模板语法引用 title 参数。

<html>
  <head>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

根据环境变量加载代码

好了,有了以上的知识。下面开始进入正题,步骤很简单,只需要把前面的知识整合起来即可。

首先引用环境变量的文件,将环境变量作为参数传入插件。

const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
const program = require('./program-argv.js')

module.exports = {
  entry: 'index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.js',
  },
  plugins: [new HtmlWebpackPlugin({
      filename: `index.html`,
      template: `./src/index.html`,
      title: '首页',
	  // 传入构建时的环境变量
	  buildEnv: program.env
  })]
}

在 index.html 使用模板语法判断环境变量按需加载代码:

<html>
  <head>
	<% if (htmlWebpackPlugin.options.buildEnv === 'prod') { %>
      <script src="https://cdn-go.cn/aegis/aegis-sdk/latest/aegis.min.js"></script>
	<% } %>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

当构建时的命令行参数为 prod 时,打包输出的 index.html 文件中就会有这段 script 标签,其他环境打包时就会彻底去掉这段代码。

在有 vue-ci 的项目中,配置方式会有些不同,需要使用 chainWebpack 为 html-webpack-plugin 传入参数:

const program = require('./program-argv.js')

module.exports = {
  // ...
  chainWebpack: (config) => {
    config
      .plugin('html')
      .tap(args => {
        args[0].buildEnv = program.env
        return args
      })
    }
  }
}

总结

本文通过工程化的方式,在构建时使用 commander 获取命令行变量,配合 html-webpack-plugin 的模板语法对文件代码进行处理,达到按需加载代码的效果。总的来说操作和理解起来并不难,就能得到一个优雅加载代码的小技巧。除了本文所讲的应用场景,还可发散思维使用这种方式应用其他的场景。

原文链接:https://juejin.cn/post/7265627782712721462 作者:出来吧皮卡丘

(0)
上一篇 2023年8月11日 上午10:15
下一篇 2023年8月11日 上午10:25

相关推荐

发表回复

登录后才能评论