Henry Henry
  • JavaScript
  • TypeScript
  • Vue
  • ElementUI
  • React
  • HTML
  • CSS
  • 技术文档
  • GitHub 技巧
  • Nodejs
  • Chrome
  • VSCode
  • Other
  • Mac
  • Windows
  • Linux
  • Vim
  • VSCode
  • Chrome
  • iTerm
  • Mac
  • Obsidian
  • lazygit
  • Vim 技巧
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • Vue 资源
GitHub (opens new window)

Henry

小学生中的前端大佬
  • JavaScript
  • TypeScript
  • Vue
  • ElementUI
  • React
  • HTML
  • CSS
  • 技术文档
  • GitHub 技巧
  • Nodejs
  • Chrome
  • VSCode
  • Other
  • Mac
  • Windows
  • Linux
  • Vim
  • VSCode
  • Chrome
  • iTerm
  • Mac
  • Obsidian
  • lazygit
  • Vim 技巧
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • Vue 资源
GitHub (opens new window)
  • 技术文档

  • GitHub

  • Nodejs

    • 打造属于自己的项目脚手架工具
    • node 和 npm 常见问题
    • node 和 npm 简介
    • 手搓一个 TinyPng 压缩图片的脚手架
    • node 监听文件夹并处理
    • 相对路径转别名路径之 chokidar
    • 脚手架性能分析
    • 自动化打包微前端多个项目
      • 自动化打包所有项目
      • 通过 git 提交记录,获取有哪些文件夹下的文件改动了
      • npm 包
        • 使用 node 实现 shell 脚本
        • 创建项目文件夹
        • 初始化 npm 包
        • 创建一个主文件入口
        • 更新 package.json
        • 本地安装
        • 发布到 npm
      • 搭配 Jenkins 实现自动化打包部署
  • Chrome

  • VSCode

  • VSCode 更新文档

  • AIGC

  • Other

  • 技术
  • Nodejs
Henry
2024-09-15
目录
自动化打包所有项目
通过 git 提交记录,获取有哪些文件夹下的文件改动了
npm 包
使用 node 实现 shell 脚本
创建项目文件夹
初始化 npm 包
创建一个主文件入口
更新 package.json
本地安装
发布到 npm
搭配 Jenkins 实现自动化打包部署

自动化打包微前端多个项目

接手了一个微前端项目,使用 iframe 技术,有一个主框架项目,其余每一个页面就是一个项目,主框架通过 iframe 引入每一个子页面。

但构建打包都是在本地进行的,再提交到 git

这样当两个人同时开发一个页面的时候,提交代码的时候肯定会冲突

就想写一个自动化打包的脚本,开发人员只提交源代码,再由一个人执行自动化打包的脚本,这样就不会出现冲突了

# 自动化打包所有项目

这个脚本的主要功能是自动打包所有的项目

所以使用 node,递归遍历当前文件夹下的所有文件夹,直到找到有 package.json 的文件夹,然后执行 npm install 和 npm run build

在项目根目录添加 install-and-build.js, 内容为:

const fs = require('fs')
const path = require('path')
const { exec } = require('child_process')

// 递归遍历目录
function findAndProcessDirectories(dir) {
  fs.readdir(dir, { withFileTypes: true }, (err, entries) => {
    if (err) {
      console.error(`无法读取目录 ${dir}: ${err}`)
      return
    }

    // 遍历目录中的每个条目
    entries.forEach(entry => {
      const fullPath = path.join(dir, entry.name)

      // 排除 node_modules 目录
      if (entry.isDirectory() && entry.name !== 'node_modules') {
        // 检查是否包含 package.json
        const packageJsonPath = path.join(fullPath, 'package.json')
        fs.access(packageJsonPath, fs.constants.F_OK, err => {
          if (!err) {
            console.log(`发现 package.json 在 ${fullPath}`)
            // 执行 npm install 和 npm run build
            exec('npm install && npm run build', { cwd: fullPath }, (error, stdout, stderr) => {
              if (error) {
                console.error(`执行命令失败:${error}`)
                return
              }
              if (stderr) {
                console.error(`标准错误:${stderr}`)
              }
              console.log(`标准输出:${stdout}`)
            })
          } else {
            // 继续递归遍历子目录
            findAndProcessDirectories(fullPath)
          }
        })
      }
    })
  })
}

// 起始目录
const startDir = process.cwd() // 使用当前工作目录
findAndProcessDirectories(startDir)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

然后在根目录执行 node install-and-build.js 即可

代码解释:

  • fs.readdir 用于读取目录内容。
  • fs.access 用于检查 package.json 是否存在。
  • exec 用于执行 shell 命令。

fs.access 是 Node.js 的 fs 模块中的一个方法,用于检查文件或目录的存在性和权限。具体来说:

fs.access(path, mode, callback) 方法的作用是检查给定路径的文件或目录是否存在,并且你是否有权限访问它。

  • path 是要检查的文件或目录的路径。
  • mode 是检查权限的类型,fs.constants.F_OK 是一个常量,表示只检查文件是否存在(即,不关心是否有读取或写入权限)。
  • callback 是一个回调函数,在检查完成后执行。如果文件或目录存在,err 参数为 null;如果不存在,则 err 参数会包含错误信息。

# 通过 git 提交记录,获取有哪些文件夹下的文件改动了

当我们的项目太多的时候,打包所有项目是很耗时的,所以我们需要通过 git 提交记录,获取有哪些文件夹下的文件改动了,只打包改动了的项目

我们可以使用 Git 的 diff 命令来列出更改的文件夹:

get-changed-dirs.sh

#!/bin/bash

# 获取上一次提交的哈希
LAST_COMMIT=$(git rev-parse HEAD)

# 获取更改的文件
CHANGED_FILES=$(git diff --name-only $LAST_COMMIT^ $LAST_COMMIT)

# 提取文件夹路径并去重
CHANGED_DIRS=$(echo "$CHANGED_FILES" | grep '/' | sed 's|/[^/]*$||' | sort -u)

# 输出更改的目录
echo "$CHANGED_DIRS"
1
2
3
4
5
6
7
8
9
10
11
12
13

这里着重解释一下这段代码:

# 提取文件夹路径并去重
CHANGED_DIRS=$(echo "$CHANGED_FILES" | grep '/' | sed 's|/[^/]*$||' | sort -u)
1
2

1 echo "$CHANGED_FILES"

  • echo "$CHANGED_FILES":输出变量  CHANGED_FILES  的内容,CHANGED_FILES  是一个包含所有更改文件路径的字符串

2 grep '/'

  • grep '/':筛选出包含斜杠  /  的行。因为文件夹路径包含斜杠,而根目录的文件名则不包含,所以这个步骤只保留路径中包含斜杠的行,即只保留文件夹路径(不包括根文件夹)。

3 sed 's|/[^/]*$||'

  • sed 's|/[^/]*$||':使用  sed  命令对每一行进行替换处理。
    • s|/[^/]*$||  是一个  sed  替换命令:
      • s|pattern|replacement|  语法用于将匹配  pattern  的部分替换为  replacement。
      • /[^/]*$  是一个正则表达式:
        • /  匹配斜杠字符。
        • [^/]*  匹配一个或多个非斜杠字符(即文件名)。
        • $  表示行尾。
      • s|/[^/]*$||  的作用是删除行尾的文件名,仅保留文件夹路径。
        • 例如,对于  /path/to/file.txt,它会变成  /path/to/。

4 sort -u

  • sort -u:对前面的结果进行排序,并去除重复项。
    • -u  选项表示唯一(unique),即删除重复的行。

这段代码的目的是从所有更改的文件路径中提取出唯一的文件夹路径。具体步骤是:

  1. 从更改的文件中筛选出包含斜杠的路径(即文件夹路径)。
  2. 去除文件名部分,只保留文件夹路径。
  3. 对路径进行排序并去除重复项,得到唯一的文件夹路径列表。

最终,CHANGED_DIRS  变量将包含所有唯一的、更改过的文件夹路径。

更新 install-and-build.js

以前是传入根目录,从根目录往下查找的,而现在使用 get-changed-dirs.sh 后,获取的是全路径了,需要从给定的全路径开始,向上逐级查找 package.json 文件,直到找到为止或者到达根目录。

同时也需要考虑避免对已经处理过的目录重复执行操作

const fs = require('fs')
const path = require('path')
const { exec } = require('child_process')

// 用于记录已经处理过的目录
const processedDirs = new Set()

// 执行 shell 脚本获取更改的文件夹
function getChangedDirectories(callback) {
  exec('./get-changed-dirs.sh', (error, stdout, stderr) => {
    if (error) {
      console.error(`执行 shell 脚本失败:${error}`)
      return
    }
    if (stderr) {
      console.error(`标准错误:${stderr}`)
    }
    // 返回目录列表
    callback(stdout.split('\n').filter(dir => dir.trim() !== ''))
  })
}

// 查找包含 package.json 的目录
function findPackageJsonDir(dir, callback) {
  const packageJsonPath = path.join(dir, 'package.json')

  // 检查当前目录是否包含 package.json
  fs.access(packageJsonPath, fs.constants.F_OK, err => {
    if (!err) {
      // 找到 package.json,执行回调
      callback(dir)
    } else {
      // 如果找不到 package.json,向上查找
      const parentDir = path.dirname(dir)
      if (parentDir !== dir) {
        // 确保不向上移动到根目录
        findPackageJsonDir(parentDir, callback)
      }
    }
  })
}

// 处理目录
function processDirectory(dir) {
  findPackageJsonDir(dir, foundDir => {
    if (processedDirs.has(foundDir)) {
      console.log(`目录 ${foundDir} 已经处理过,跳过。`)
      return
    }
    processedDirs.add(foundDir)

    console.log(`发现 package.json 在 ${foundDir}`)
    // 执行 npm install 和 npm run build
    exec('npm install && npm run build', { cwd: foundDir }, (error, stdout, stderr) => {
      if (error) {
        console.error(`执行命令失败:${error}`)
        return
      }
      if (stderr) {
        console.error(`标准错误:${stderr}`)
      }
      console.log(`标准输出:${stdout}`)
    })
  })
}

// 修改后的 findAndProcessDirectories 函数
function findAndProcessDirectories(dirs) {
  dirs.forEach(dir => {
    processDirectory(dir)
  })
}

// 执行主逻辑
getChangedDirectories(changedDirs => {
  findAndProcessDirectories(changedDirs)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

如果遇到“permission denied”错误,通常是因为脚本没有执行权限

可以使用以下命令来设置权限:

chmod +x get-changed-dirs.sh
1

# npm 包

上面代码已经实现了,但是我们还需要生成一个自动化打包的 npm 包,这样就不需要在根目录创建 install-and-build.js 了,以后再有这种微前端项目也可以自动化打包

但还有两个问题:

  • Shell 脚本和跨平台兼容性:由于 get-changed-dirs.sh 是一个 Bash 脚本,它在 Windows 上可能无法直接执行。如果需要支持跨平台,需要使用 Node.js 实现
  • 执行权限:在发布之前确保脚本有正确的执行权限,并在发布后的文档中提供如何使用的说明。

# 使用 node 实现 shell 脚本

所以我们还是用 node 实现一下吧

get-changed-dirs.js

const { exec } = require('child_process')

// 获取更改的文件夹
function getChangedDirectories(callback) {
  exec('git diff --name-only HEAD^ HEAD', (error, stdout, stderr) => {
    if (error) {
      console.error(`执行命令失败:${error}`)
      return
    }
    if (stderr) {
      console.error(`标准错误:${stderr}`)
    }

    // 提取目录路径并去重
    const changedDirs = stdout
      .split('\n')
      .filter(file => file.includes('/'))
      .map(file => file.substring(0, file.lastIndexOf('/')))
      .filter((value, index, self) => self.indexOf(value) === index)

    callback(changedDirs)
  })
}

module.exports = getChangedDirectories
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

然后在 install-and-build.js 中调用这个新脚本:

const getChangedDirectories = require('./get-changed-dirs')

// 执行主逻辑
getChangedDirectories(changedDirs => {
  findAndProcessDirectories(changedDirs)
})
1
2
3
4
5
6

这样就可以了

创建一个 npm 包还是很简单的,网上有一大堆资料,也可以参考这个打造属于自己的项目脚手架工具,不过就是这个例子复杂了一点

这里就简单写一下了:

# 创建项目文件夹

multiple-build

# 初始化 npm 包

执行 npm init -y

# 创建一个主文件入口

在项目根目录中,创建一个 index.js 文件,作为 npm 包的入口文件。将 install-and-build.js 代码添加到 index.js 中:

#!/usr/bin/env node

// install-and-build.js
1
2
3

# 更新 package.json

在 package.json 文件中,添加一个 bin 字段,将 index.js 文件指定为命令行工具的入口

# 本地安装

使用 npm link 将当前 npm 包链接到全局执行环境,这样在任何目录都可以执行 multiple-build 命令来自动化打包所有项目

使用 multiple-build 测试没问题就可以发布到 npm 了

# 发布到 npm

运行 npm publish 来发布到 npm

# 搭配 Jenkins 实现自动化打包部署

由于 Jenkins 由公司统一管理,所以一切基本配置均已完成,我们只需要少量配置即可

所以在构建步骤中添加命令即可:

npm i multiple-build -g && multiple-build
1

如需完整流程,请参考 搭配 Jenkins 实现自动化打包微前端多个项目

编辑 (opens new window)
上次更新: 9/15/2024, 11:00:05 AM
脚手架性能分析
chrome 扩展插件

← 脚手架性能分析 chrome 扩展插件→

最近更新
01
搭配 Jenkins 实现自动化打包微前端多个项目
09-15
02
el-upload 直传阿里 oss 并且显示自带进度条和视频回显封面图
06-05
03
version 1.25
06-03
更多文章>

Related Issues not found

Please contact @HenryTSZ to initialize the comment

Theme by Vdoing | Copyright © 2017-2025 HenryTSZ | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式