UNPKG

boostr

Version:
118 lines 5.21 kB
import { join } from 'path'; import bytes from 'bytes'; import isEmpty from 'lodash/isEmpty.js'; import { requireGlobalNPMPackage, installNPMPackages, findInstalledNPMPackage } from './npm.js'; import { logMessage, logError, throwError, resolveVariables, getFileSize } from './utilities.js'; const ESBUILD_PACKAGE_VERSION = '0.16.15'; export async function build({ serviceDirectory, entryPoint, buildDirectory, bundleFileNameWithoutExtension = 'bundle', bootstrapTemplate, bootstrapVariables = {}, serviceName, environment = {}, external = [], builtInExternal = [], sourceMap = false, minify = false, freeze = false, installExternalDependencies = false, watch = false, esbuildOptions }) { if (freeze && watch) { throw Error("You cannot use both 'freeze' and 'watch'"); } const bootstrapCode = resolveVariables(bootstrapTemplate, { ...bootstrapVariables, entryPoint }); // Include CLI's node_modules folder so that packages such as @layr/component-http-server // or @layr/aws-integration can be found even though they are not installed by the user const nodePaths = [new URL('../node_modules', import.meta.url).pathname]; const definedIdentifiers = esbuildOptions?.define ?? {}; for (const [name, value] of Object.entries(environment)) { definedIdentifiers[`process.env.${name}`] = `"${value}"`; } const { build } = await requireGlobalNPMPackage('esbuild', ESBUILD_PACKAGE_VERSION, { serviceName }); let jsBundleFile; let cssBundleFile; let result; try { result = await build({ absWorkingDir: serviceDirectory, outdir: buildDirectory, stdin: { contents: bootstrapCode, resolveDir: serviceDirectory, sourcefile: 'bootstrap.js' }, nodePaths, bundle: true, entryNames: freeze ? `${bundleFileNameWithoutExtension}-[hash].immutable` : bundleFileNameWithoutExtension, assetNames: freeze ? '[name]-[hash].immutable' : '[name]', define: definedIdentifiers, external: [...external, ...builtInExternal], metafile: true, loader: { '.js': 'ts', '.jsx': 'tsx', '.png': 'file', '.jpeg': 'file', '.jpg': 'file', '.gif': 'file', '.webp': 'file', '.svg': 'file', '.svgz': 'file' }, sourcemap: sourceMap, ...(minify && { minify: true, keepNames: true }), ...(watch !== false && { watch: { onRebuild: (error) => { if (error) { logError('Rebuild failed', { serviceName }); } else { logMessage(`Rebuild succeeded (bundle size: ${bytes(getFileSize(jsBundleFile))})`, { serviceName }); if (typeof watch === 'object' && watch.afterRebuild !== undefined) { watch.afterRebuild(); } } } } }), ...esbuildOptions }); } catch { throwError('Build failed', { serviceName }); } if (installExternalDependencies) { const externalDependencies = {}; for (const packageName of external) { const externalPackage = findInstalledNPMPackage(serviceDirectory, packageName); if (externalPackage === undefined) { throwError(`Couldn't find the npm package '${packageName}' specified as an external dependency`, { serviceName }); } externalDependencies[packageName] = externalPackage.version; } if (!isEmpty(externalDependencies)) { logMessage('Installing external dependencies...', { serviceName }); await installNPMPackages(buildDirectory, externalDependencies); } } ({ jsBundleFile, cssBundleFile } = determineFileBundlesFromBuildResult(result, { serviceDirectory, serviceName })); logMessage(`Build succeeded (bundle size: ${bytes(getFileSize(jsBundleFile))})`, { serviceName }); return { jsBundleFile, cssBundleFile }; } function determineFileBundlesFromBuildResult(result, { serviceDirectory, serviceName }) { let jsBundleFile; let cssBundleFile; const outputs = result?.metafile?.outputs ?? {}; for (const [file, output] of Object.entries(outputs)) { if (output.entryPoint === 'bootstrap.js') { jsBundleFile = join(serviceDirectory, file); } else if (file.endsWith('.css')) { cssBundleFile = join(serviceDirectory, file); } } if (jsBundleFile === undefined) { throwError("Couldn't determine the name of generated bundle", { serviceName }); } return { jsBundleFile, cssBundleFile }; } //# sourceMappingURL=builder.js.map