f2e-server3
Version:
f2e-server 3.0
96 lines (88 loc) • 3.85 kB
text/typescript
import * as fs from 'node:fs';
import path from "node:path";
import * as _ from '../../utils/misc'
import { code_define, code_externals } from "../../utils/templates";
import { VERSION } from "../../utils/engine";
import { EsbuildConfig } from './interface';
import { BuildOptions, BuildResult } from 'esbuild';
import crypto from 'node:crypto';
export const default_config: Required<EsbuildConfig> = {
esbuildrc: '.esbuildrc.js',
esbuildOptions: {},
build_external: true,
with_metafile: false,
reg_inject: /index\.html$/,
reg_replacer: /<script\s.*?src="(.*?)".*?>\s*<\/script\>/g,
cache_root: '.f2e_cache',
inject_global_name: '__f2e_esbuild_inject__',
external_lib_name: 'external_lib',
}
export const generate_global_name = (inject_global_name: string, lib_hash: string) => `window.${inject_global_name}${lib_hash ? `_${lib_hash}` : ''}`
export const generate_filename = (filename: string, hash: string) => {
const ext = path.extname(filename)
return `${path.basename(filename, ext)}${hash ? `_${hash}` : ''}.ts`
}
export const generate_inject_code = (inject_global_name: string, lib_hash: string, is_dev: boolean) => {
return _.template(code_define, { VERSION, GLOBAL_NAME: generate_global_name(inject_global_name, lib_hash), is_dev })
}
export const generate_externals_code = (inject_global_name: string, external: string[], lib_hash: string) => {
return _.template(code_externals, { external, GLOBAL_NAME: generate_global_name(inject_global_name, lib_hash) })
}
export const generate_banner_code = (inject_global_name: string, lib_hash: string) => {
if (!lib_hash) {
return ''
}
const GLOBAL_NAME = generate_global_name(inject_global_name, lib_hash)
return `\nrequire = ${GLOBAL_NAME} && ${GLOBAL_NAME}.require;`
}
const write_cache_file = (cache_path: string, filename: string, code: string) => {
if (!fs.existsSync(cache_path)) {
fs.mkdirSync(cache_path, { recursive: true })
}
fs.writeFileSync(path.join(cache_path, filename), code)
}
export const generate_hash = (modules: string[], system_hash: string) => {
if (modules.length === 0) {
return ''
}
return crypto.createHash('md5').update(modules.sort().join(',') + system_hash).digest('hex').slice(0, 8)
}
export interface BuildExternalFileOptions {
filename: string;
conf: EsbuildConfig;
modules: string[];
lib_hash: string;
}
export const build_external_file = ({ filename, conf, modules, lib_hash }: BuildExternalFileOptions) => {
const {
cache_root = default_config.cache_root,
inject_global_name = default_config.inject_global_name,
} = conf
if (fs.existsSync(path.join(cache_root, filename))) {
// 已经编译过的不再编译
return
}
const js_code = generate_externals_code(inject_global_name, modules, lib_hash)
write_cache_file(cache_root, filename, js_code)
}
export const getEntryPaths = (entryPoints: BuildOptions['entryPoints']) => {
const paths: {in: string, out: string}[] = []
if (Array.isArray(entryPoints)) {
for (const entry of entryPoints) {
if (typeof entry === 'string') {
paths.push({in: entry, out: entry})
} else {
paths.push(entry)
}
}
} else if (entryPoints) {
Object.entries(entryPoints).forEach((item: [string, string]) => {
paths.push({in: item[1], out: item[0]})
})
}
return paths
}
export const build_css_paths = (result: BuildResult, root: string) => {
return result?.outputFiles?.filter(_outputFile => _outputFile.path.endsWith('.css'))
.map(_outputFile => _.pathname_fixer(path.relative(root, _outputFile.path))) || []
}