UNPKG

@roxi/routify

Version:

111 lines (95 loc) 3.29 kB
import { relativeUnix } from '../../../buildtime/utils.js' import fse from 'fs-extra' import { resolve } from 'path' class Bundles { constructor(outputDir) { this.outputDir = outputDir } /** @type {Object.<string, Bundle>} */ bundles = {} /** @param {RNodeBuildtime} node */ upsert(node) { const { path } = node.file this.bundles[path] = this.bundles[path] || new Bundle(node, this.outputDir) return this.bundles[path] } async apply() { return Promise.all(Object.values(this.bundles).map(bundle => bundle.apply())) } } class Bundle { /** @type {RNodeBuildtime[]} */ members = [] /** * @param {RNodeBuildtime} node * @param {string} outputDir * */ constructor(node, outputDir) { this.outputDir = outputDir this.instructor = node this.filename = 'bundles/bundle-' + node.id + '.js' } include(node) { this.members.push(node) } async apply() { fse.ensureDirSync(this.outputDir) const output = resolve(this.outputDir, this.filename) const exportStr = this.members .map( node => `export * as ${node.id} from '${relativeUnix( this.outputDir + '/bundles', node.module, )}'`, ) .join('\n') this.members.forEach(node => { // if root prebundle, else codesplit bundle if (this.instructor.isRoot) node.module = `bundle_${this.instructor.id}.${node.id}::_EVAL` else { node.asyncModule = `() => import("./${this.filename}").then(r => r.${node.id})::_EVAL` delete node.module } }) await this.instructor.instance.writeFile(output, [exportStr].join('\n')) } } const bundleIsNotNullOrUndefined = val => ![null, undefined].includes(val.meta.bundle) /** * * @param {RNodeBuildtime} node * @param {any} outputDir */ export const createBundles = async (node, outputDir) => { const { routifyDir } = node.instance.options const bundles = new Bundles(outputDir) const nodes = [node, ...node.descendants].filter(node => node.module) // iterate node and its descendants for (node of nodes) { // look for nearest instructions in node and its ancestors const bundleInstructionsNode = [node, ...node.ancestors].find( bundleIsNotNullOrUndefined, ) if (bundleInstructionsNode?.meta.bundle) { const bundle = bundles.upsert(bundleInstructionsNode) bundle.include(node) // bundle file } else { const path = relativeUnix(routifyDir, node.module) const prefix = path.startsWith('../') ? '' : './' node.asyncModule = `() => import('${prefix + path}')::_EVAL` //codesplit file delete node.module } } await bundles.apply() } /** * @param {RoutifyBuildtimePayload} param0 */ export const bundler = async ({ instance }) => { const promises = Object.values(instance.rootNodes).map(rootNode => createBundles(rootNode, instance.options.routifyDir), ) return await Promise.all(promises) }