一个小小的webpack插件

这个插件会读取项目根目录下的 package.json 文件来获取版本号,并记录当前的构建时间。

1. 插件代码 (version-info-plugin.js)

在你的项目根目录(或者任何你方便引用的地方,例如 plugins/ 文件夹)创建一个新文件,命名为 version-info-plugin.js

js 复制代码
// version-info-plugin.js
const path = require('path');
const fs = require('fs');
// 如果需要获取 Git Commit Hash,可以引入 child_process
// const { execSync } = require('child_process');

class VersionInfoPlugin {
  constructor(options = {}) {
    this.options = {
      filename: 'version.json', // 默认生成的文件名
      // 你可以在这里添加更多选项,例如指定 package.json 的路径
      // packageJsonPath: path.resolve(process.cwd(), 'package.json'),
      ...options
    };
  }

  apply(compiler) {
    // 1. 获取 package.json 中的版本信息
    const packageJsonPath = path.resolve(compiler.context, 'package.json');
    let packageVersion = 'N/A'; // 默认值,如果读取失败
    
    try {
      const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
      const packageJson = JSON.parse(packageJsonContent);
      packageVersion = packageJson.version || 'N/A';
    } catch (error) {
      console.warn(
        `[VersionInfoPlugin] 警告: 无法读取 package.json 文件或解析其内容。` +
        `请确保文件存在且格式正确。路径: ${packageJsonPath}. 错误: ${error.message}`
      );
    }

    // 2. 监听 Webpack 的 'emit' 钩子
    // 'emit' 钩子在 Webpack 将所有资源输出到 output 目录之前触发。
    // 这是一个异步钩子,所以我们使用 tapAsync。
    compiler.hooks.emit.tapAsync(
      'VersionInfoPlugin', // 插件名称,用于调试和错误报告
      (compilation, callback) => {
        // 3. 构建版本信息对象
        const versionInfo = {
          version: packageVersion,
          buildTime: new Date().toISOString(), // ISO 8601 格式的构建时间
          // 4. (可选) 获取 Git Commit Hash
          // try {
          //   versionInfo.gitCommit = execSync('git rev-parse HEAD').toString().trim();
          // } catch (gitError) {
          //   console.warn('[VersionInfoPlugin] 警告: 无法获取 Git Commit Hash。请确保项目是 Git 仓库。');
          //   versionInfo.gitCommit = 'N/A';
          // }
        };

        // 将版本信息对象转换为格式化的 JSON 字符串
        const jsonContent = JSON.stringify(versionInfo, null, 2); // null, 2 用于美化输出,2 个空格缩进

        // 5. 将生成的 JSON 文件添加到 Webpack 的资源列表中
        // compilation.assets 是一个对象,键是文件名,值是包含 source() 和 size() 方法的对象
        compilation.assets[this.options.filename] = {
          source: () => jsonContent, // source 方法返回文件内容
          size: () => jsonContent.length, // size 方法返回文件大小
        };

        console.log(
          `[VersionInfoPlugin] 已生成 ${this.options.filename} 文件。` +
          `版本: ${versionInfo.version}, 构建时间: ${versionInfo.buildTime}`
        );

        // 6. 调用 callback,通知 Webpack 异步操作已完成
        callback();
      }
    );
  }
}

module.exports = VersionInfoPlugin;

2. webpack.config.js 配置

在你的 webpack.config.js 文件中引入并使用这个自定义插件。

js 复制代码
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 假设你使用了 html-webpack-plugin
const VersionInfoPlugin = require('./version-info-plugin'); // 引入你的自定义插件

module.exports = {
  mode: 'production', // 或 'development'
  entry: './src/index.js', // 你的入口文件
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true, // 每次构建前清理 dist 目录
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html', // 你的 HTML 模板文件
    }),
    // 实例化你的自定义插件
    new VersionInfoPlugin({
      // 可选:如果你想改变生成的文件名,例如:
      // filename: 'app-build-info.json',
    }),
  ],
  devServer: {
    static: path.resolve(__dirname, 'dist'), // 开发服务器静态文件目录
    port: 8080,
    open: true, // 启动后自动打开浏览器
  },
};

3. package.json 示例

确保你的项目根目录有一个 package.json 文件,并且其中包含 version 字段。

json 复制代码
{
  "name": "my-frontend-app",
  "version": "1.0.0", // 这个版本号会被插件读取
  "description": "一个简单的前端应用",
  "main": "src/index.js",
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "start": "webpack serve --config webpack.config.js"
  },
  "keywords": [],
  "author": "Your Name",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^5.x.x",
    "webpack": "^5.x.x",
    "webpack-cli": "^5.x.x",
    "webpack-dev-server": "^5.x.x"
  }
}

4. 前端代码中如何访问 version.json (src/index.jspublic/index.html)

在你的前端应用中,你可以通过 HTTP 请求(例如 fetch)来加载这个 version.json 文件。

public/index.html 示例:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>我的前端应用</title>
</head>
<body>
    <h1>欢迎来到我的应用</h1>
    <p>应用版本: <span id="app-version">加载中...</span></p>
    <p>构建时间: <span id="build-time">加载中...</span></p>
    <!-- Webpack 会自动注入 bundle.js -->
</body>
</html>

src/index.js 示例:

js 复制代码
// src/index.js

// 假设 version.json 会被输出到 dist 目录的根部
fetch('/version.json')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP 错误! 状态码: ${response.status}`);
    }
    return response.json();
  })
  .then(versionInfo => {
    console.log('获取到的版本信息:', versionInfo);
    document.getElementById('app-version').textContent = versionInfo.version;
    // 格式化构建时间以便更好地显示
    document.getElementById('build-time').textContent = new Date(versionInfo.buildTime).toLocaleString();
  })
  .catch(error => {
    console.error('加载 version.json 失败:', error);
    document.getElementById('app-version').textContent = '加载失败';
    document.getElementById('build-time').textContent = '加载失败';
  });

console.log('前端应用已启动!');

5. 运行和验证

  1. 确保你的项目结构如下:

    bash 复制代码
    my-frontend-app/
    ├── package.json
    ├── webpack.config.js
    ├── version-info-plugin.js
    ├── public/
    │   └── index.html
    └── src/
        └── index.js
  2. 安装所有依赖:

    bash 复制代码
    npm install
  3. 运行构建命令:

    bash 复制代码
    npm run build
  4. 构建完成后,检查 dist 目录,你会发现一个 version.json 文件,内容类似:

    bash 复制代码
    {
      "version": "1.0.0",
      "buildTime": "2025-06-02T06:20:03.123Z"
    }
  5. 启动开发服务器:

    bash 复制代码
    npm start
  6. 在浏览器中打开 http://localhost:8080,你应该能看到页面上显示了从 version.json 中读取到的版本号和构建时间。

这个插件提供了一个基础且实用的功能,你可以根据自己的需求进行扩展,例如添加 Git Commit Hash、构建环境信息等。

相关推荐
HUMHSX10 小时前
Vue 项目启动全流程解析:从入口文件到全局指令注册与页面渲染
前端·javascript·vue.js
有颜有货10 小时前
PMC生产排产的4种算法,一次讲清
java·服务器·前端
小虎牙00710 小时前
Android kotlin图片库Coil源码详解
android·前端
随风一样自由10 小时前
【前端领域】前端开发核心应用场景与落地实践
前端·前端框架
an3174211 小时前
弹窗数据流设计的两种高阶架构实践
前端·vue.js·架构
谢尔登11 小时前
【React】 状态管理方案
前端·react.js·前端框架
用户21366100357211 小时前
Vue商品详情与放大镜组件
前端·javascript
半个落月11 小时前
从Tapas小Demo理清localStorage、事件与this
前端·javascript
李明卫杭州11 小时前
Vue2 中 v-model 处理不同数据结构的技巧
前端·javascript·vue.js
李明卫杭州11 小时前
使用 computed 处理 v-model 复杂数据结构
前端·javascript·vue.js