#!/usr/bin/node const start = Date.now() const fs = require("fs") const { readdir, copyFile, mkdir } = require('node:fs/promises'); const path = require("path") const { build } = require("esbuild") const { compile } = require('svelte/compiler') const { default: TsconfigPathsPlugin, } = require("@esbuild-plugins/tsconfig-paths") const { nodeExternalsPlugin } = require("esbuild-node-externals") const svelteCompilePlugin = { name: 'svelteCompile', setup(build) { // This resolve handler is necessary to bundle the Svelte runtime into the the final output, // otherwise the bundled script will attempt to resolve it at runtime build.onResolve({ filter: /svelte\/internal/ }, async () => { return { path: `${process.cwd()}/../../node_modules/svelte/src/runtime/internal/ssr.js` } }) // Compiles `.svelte` files into JS classes so that they can be directly imported into our // Typescript packages build.onLoad({ filter: /\.svelte$/ }, async (args) => { const source = await fs.promises.readFile(args.path, 'utf8') const dir = path.dirname(args.path); try { const { js } = compile(source, { css: "injected", generate: "ssr" }) return { // The code placed in the generated file contents: js.code, // The loader this is passed to, basically how the above provided content is "treated", // the contents provided above will be transpiled and bundled like any other JS file. loader: 'js', // Where to resolve any imports present in the loaded file resolveDir: dir } } catch (e) { return { errors: [JSON.stringify(e)] } } }) } } var { argv } = require("yargs") async function runBuild(entry, outfile) { const isDev = process.env.NODE_ENV !== "production" const tsconfig = argv["p"] || `tsconfig.build.json` const tsconfigPathPluginContent = JSON.parse( fs.readFileSync(tsconfig, "utf-8") ) if ( !fs.existsSync(path.join(__dirname, "../packages/pro/src")) && tsconfigPathPluginContent.compilerOptions?.paths ) { // If we don't have pro, we cannot bundle backend-core. // Otherwise, the main context will not be shared between libraries delete tsconfigPathPluginContent?.compilerOptions?.paths?.[ "@budibase/backend-core" ] delete tsconfigPathPluginContent?.compilerOptions?.paths?.[ "@budibase/backend-core/*" ] } const sharedConfig = { entryPoints: [entry], bundle: true, minify: !isDev, sourcemap: isDev, tsconfig, plugins: [ svelteCompilePlugin, TsconfigPathsPlugin({ tsconfig: tsconfigPathPluginContent }), nodeExternalsPlugin(), ], preserveSymlinks: true, loader: { }, metafile: true, external: [ "deasync", "mock-aws-s3", "nock", "bull", "pouchdb", "bcrypt", "bcryptjs", "graphql/*", "bson", ], } await mkdir('dist', { recursive: true }); const hbsFiles = (async () => { const dir = await readdir('./', { recursive: true }); const files = dir.filter(entry => entry.endsWith('.hbs') || entry.endsWith('ivm.bundle.js')); const fileCopyPromises = files.map(file => copyFile(file, `dist/${path.basename(file)}`)) await Promise.all(fileCopyPromises) })() const mainBuild = build({ ...sharedConfig, platform: "node", outfile, }) await Promise.all([hbsFiles, mainBuild]) fs.writeFileSync( `dist/${path.basename(outfile)}.meta.json`, JSON.stringify((await mainBuild).metafile) ) console.log( "\x1b[32m%s\x1b[0m", `Build successfully in ${(Date.now() - start) / 1000} seconds` ) } if (require.main === module) { const entry = argv["e"] || "./src/index.ts" const outfile = `dist/${entry.split("/").pop().replace(".ts", ".js")}` runBuild(entry, outfile) } else { module.exports = runBuild }