UNPKG

f2e-server3

Version:

f2e-server 3.0

117 lines (111 loc) 5.44 kB
import { MemoryTree } from "./interface" import * as _ from '../utils/misc' import { defaultOptions } from './defaults' import { inputProvider, beginWatch } from "./input" import { outputProvider } from "./output" import path from 'node:path' import { createHash } from "node:crypto" import logger from "../utils/logger" import { isArrayBufferView } from "node:util/types" export * from "./interface" export * from "./defaults" const inEntries = (entries: string[] = [], pathname: string) => { return entries.find(item => new RegExp(item).test(pathname)) } export const createStore = function (options: Pick<MemoryTree.Options, 'onGet'|'namehash'|'watch'>): MemoryTree.Store { const { onGet, namehash, watch } = options let o = {} const origin_map = new Map<string, MemoryTree.SetResult>() const output_map = new Map<string, string>() const store: MemoryTree.Store = { ignores: new Set(), origin_map, output_map, _get(pathname) { const arr = _.pathname_arr(pathname) return arr.length ? _.get(o, arr) : o }, async load (_pathname) { const pathname = _.pathname_fixer(_pathname) let result = await onGet(pathname, store._get(pathname), store) if (result && namehash && namehash.entries && namehash.searchValue) { if (inEntries(namehash.entries, pathname)) { const searchValues = namehash.searchValue.map(t => new RegExp(t, 'g')) result = result.toString() for (let i = 0; i < searchValues.length; i++) { const searchValue = searchValues[i] const replacer = (mat: string, src: string) => { const key = /^https?:\/\//.test(src) ? src : ( _.pathname_fixer('/' === src.charAt(0) ? src : path.join(path.dirname(pathname), src)) ) const out = origin_map.get(key) if (!out) return mat const targetSrc = (namehash.publicPath || '/') + out.outputPath.replace(/^\/+/, '') return mat.replace(src, targetSrc + (watch ? `" data-origin="${key}" data-hash="${out.hash}"` : '')) } result = result.replace(searchValue, replacer) } } } return result }, save(result) { // outputPath 需要携带根路径 / if (namehash && (isArrayBufferView(result.data) || typeof result.data === 'string')) { const hash = createHash('md5').update(result.data).digest('hex').slice(0, 8) result.hash = hash if (namehash.replacer) { if (!inEntries(namehash?.entries, result.originPath)) { result.outputPath = namehash.replacer(_.pathname_fixer(result.outputPath || result.originPath), hash) || result.outputPath } else if (namehash.searchValue && watch) { const searchValues = namehash.searchValue.map(t => new RegExp(t, 'g')) const context = result.data.toString() const deps: string[] = [] for (let i = 0; i < searchValues.length; i++) { const searchValue = searchValues[i] context.replace(searchValue, (mat: string, src: string) => { const key = /^https?:\/\//.test(src) ? src : ( _.pathname_fixer('/' === src.charAt(0) ? src : path.join(path.dirname(result.originPath), src)) ) deps.push(key) return mat }) } result.deps = deps } } } result.updateTime = + new Date() if (result.error) { logger.error(`${result.originPath} -> ${result.outputPath}`, result.error) origin_map.set(result.originPath, result) return } origin_map.set(result.originPath, result) if (result.originPath) { output_map.set(_.pathname_fixer(result.outputPath), result.originPath) _.set(o, _.pathname_fixer(result.outputPath), result.data ) } if(!_.isPlainObject(result.data)) { logger.debug(`save ${result.originPath} -> ${result.outputPath}`) } }, } return store } export const createMemoryTree = (options: Partial<MemoryTree.Options>): MemoryTree.MemoryTree => { const _options: MemoryTree.Options = { ...defaultOptions, ...(options || {}), } const { onGet, namehash, watch } = _options const store = createStore({ onGet, namehash, watch }) const build = inputProvider(_options, store) return { store, input: build, output: outputProvider(_options, store), watch: beginWatch(_options, store, build), } } export default createMemoryTree