build: reuse const enum data between concurrent rollup builds

This commit is contained in:
Evan You 2023-02-06 09:35:08 +08:00
parent 72b570917e
commit 39cf4cd30b
3 changed files with 55 additions and 21 deletions

View File

@ -32,7 +32,7 @@ const pkg = require(resolve(`package.json`))
const packageOptions = pkg.buildOptions || {} const packageOptions = pkg.buildOptions || {}
const name = packageOptions.filename || path.basename(packageDir) const name = packageOptions.filename || path.basename(packageDir)
const [enumPlugin, enumDefines] = await constEnum() const [enumPlugin, enumDefines] = constEnum()
const outputConfigs = { const outputConfigs = {
'esm-bundler': { 'esm-bundler': {

View File

@ -17,7 +17,7 @@ nr build core --formats cjs
*/ */
import fs from 'node:fs/promises' import fs from 'node:fs/promises'
import { existsSync, readFileSync } from 'node:fs' import { existsSync, readFileSync, rmSync } from 'node:fs'
import path from 'node:path' import path from 'node:path'
import minimist from 'minimist' import minimist from 'minimist'
import { gzipSync } from 'node:zlib' import { gzipSync } from 'node:zlib'
@ -27,6 +27,7 @@ import execa from 'execa'
import { cpus } from 'node:os' import { cpus } from 'node:os'
import { createRequire } from 'node:module' import { createRequire } from 'node:module'
import { targets as allTargets, fuzzyMatchTarget } from './utils.js' import { targets as allTargets, fuzzyMatchTarget } from './utils.js'
import { scanEnums } from './const-enum.js'
const require = createRequire(import.meta.url) const require = createRequire(import.meta.url)
const args = minimist(process.argv.slice(2)) const args = minimist(process.argv.slice(2))
@ -42,6 +43,8 @@ const commit = execa.sync('git', ['rev-parse', 'HEAD']).stdout.slice(0, 7)
run() run()
async function run() { async function run() {
const removeCache = scanEnums()
try {
if (!targets.length) { if (!targets.length) {
await buildAll(allTargets) await buildAll(allTargets)
checkAllSizes(allTargets) checkAllSizes(allTargets)
@ -49,6 +52,9 @@ async function run() {
await buildAll(fuzzyMatchTarget(targets, buildAllMatching)) await buildAll(fuzzyMatchTarget(targets, buildAllMatching))
checkAllSizes(fuzzyMatchTarget(targets, buildAllMatching)) checkAllSizes(fuzzyMatchTarget(targets, buildAllMatching))
} }
} finally {
removeCache()
}
} }
async function buildAll(targets) { async function buildAll(targets) {

View File

@ -15,31 +15,37 @@
*/ */
import execa from 'execa' import execa from 'execa'
import { readFileSync } from 'node:fs' import {
existsSync,
readFileSync,
rmSync,
writeFile,
writeFileSync
} from 'node:fs'
import { parse } from '@babel/parser' import { parse } from '@babel/parser'
import path from 'node:path' import path from 'node:path'
import MagicString from 'magic-string' import MagicString from 'magic-string'
const ENUM_CACHE_PATH = 'temp/enum.json'
function evaluate(exp) { function evaluate(exp) {
return new Function(`return ${exp}`)() return new Function(`return ${exp}`)()
} }
// this is called in the build script entry once
// so the data can be shared across concurrent Rollup processes
export function scanEnums() {
/** /**
* @returns {Promise<[import('rollup').Plugin, Record<string, string>]>} * @type {{ ranges: Record<string, [number, number][]>, defines: Record<string, string>, ids: string[] }}
*/
export async function constEnum() {
/**
* @type {{ ranges: Record<string, [number, number][]>, defines: Record<string, string> }}
*/ */
const enumData = { const enumData = {
ranges: {}, ranges: {},
defines: {} defines: {},
ids: []
} }
const knowEnums = new Set()
// 1. grep for files with exported const enum // 1. grep for files with exported const enum
const { stdout } = await execa('git', ['grep', `export const enum`]) const { stdout } = execa.sync('git', ['grep', `export const enum`])
const files = [...new Set(stdout.split('\n').map(line => line.split(':')[0]))] const files = [...new Set(stdout.split('\n').map(line => line.split(':')[0]))]
// 2. parse matched files to collect enum info // 2. parse matched files to collect enum info
@ -70,7 +76,9 @@ export async function constEnum() {
for (let i = 0; i < decl.members.length; i++) { for (let i = 0; i < decl.members.length; i++) {
const e = decl.members[i] const e = decl.members[i]
const id = decl.id.name const id = decl.id.name
knowEnums.add(id) if (!enumData.ids.includes(id)) {
enumData.ids.push(id)
}
const key = e.id.type === 'Identifier' ? e.id.name : e.id.value const key = e.id.type === 'Identifier' ? e.id.name : e.id.value
const fullKey = `${id}.${key}` const fullKey = `${id}.${key}`
const init = e.initializer const init = e.initializer
@ -149,9 +157,29 @@ export async function constEnum() {
} }
} }
// 3. save cache
writeFileSync(ENUM_CACHE_PATH, JSON.stringify(enumData))
return () => {
rmSync(ENUM_CACHE_PATH, { force: true })
}
}
/**
* @returns {[import('rollup').Plugin, Record<string, string>]}
*/
export function constEnum() {
if (!existsSync(ENUM_CACHE_PATH)) {
throw new Error('enum cache needs to be initialized before creating plugin')
}
/**
* @type {{ ranges: Record<string, [number, number][]>, defines: Record<string, string>, ids: string[] }}
*/
const enumData = JSON.parse(readFileSync(ENUM_CACHE_PATH, 'utf-8'))
// construct a regex for matching re-exports of known const enums // construct a regex for matching re-exports of known const enums
const reExportsRE = new RegExp( const reExportsRE = new RegExp(
`export {[^}]*?\\b(${[...knowEnums].join('|')})\\b[^]*?}` `export {[^}]*?\\b(${enumData.ids.join('|')})\\b[^]*?}`
) )
// 3. during transform: // 3. during transform:
@ -190,7 +218,7 @@ export async function constEnum() {
if ( if (
spec.type === 'ExportSpecifier' && spec.type === 'ExportSpecifier' &&
spec.exportKind !== 'type' && spec.exportKind !== 'type' &&
knowEnums.has(spec.local.name) enumData.ids.includes(spec.local.name)
) { ) {
const next = node.specifiers[i + 1] const next = node.specifiers[i + 1]
if (next) { if (next) {