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

前言

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

js 复制代码
<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:

js 复制代码
"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 模块。它提供了一种简单和灵活的方式来创建和管理命令行,使开发者能够轻松地定义命令、选项和参数。

安装它:

bash 复制代码
npm install commander -D

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

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 的时候引用该文件进行获取命令行参数:

js 复制代码
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 参数。

js 复制代码
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 复制代码
<html>
  <head>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

根据环境变量加载代码

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

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

js 复制代码
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 复制代码
<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 传入参数:

javascript 复制代码
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 的模板语法对文件代码进行处理,达到按需加载代码的效果。总的来说操作和理解起来并不难,就能得到一个优雅加载代码的小技巧。除了本文所讲的应用场景,还可发散思维使用这种方式应用其他的场景。

相关推荐
Martin -Tang34 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发34 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁2 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂2 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成5 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽5 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新6 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html