2023-05-19 22:55:29 +03:00
|
|
|
/** @file Configuration for the esbuild bundler and build/watch commands.
|
2023-03-31 17:19:07 +03:00
|
|
|
*
|
|
|
|
* The bundler processes each entry point into a single file, each with no external dependencies and
|
|
|
|
* minified. This primarily involves resolving all imports, along with some other transformations
|
|
|
|
* (like TypeScript compilation).
|
|
|
|
*
|
|
|
|
* See the bundlers documentation for more information:
|
2023-05-19 22:55:29 +03:00
|
|
|
* https://esbuild.github.io/getting-started/#bundling-for-node. */
|
2023-03-31 17:19:07 +03:00
|
|
|
import * as fs from 'node:fs/promises'
|
|
|
|
import * as path from 'node:path'
|
|
|
|
import * as url from 'node:url'
|
|
|
|
|
|
|
|
import * as esbuildPluginNodeModules from '@esbuild-plugins/node-modules-polyfill'
|
2024-01-10 19:22:11 +03:00
|
|
|
import type * as esbuild from 'esbuild'
|
2023-09-22 06:43:25 +03:00
|
|
|
import esbuildPluginInlineImage from 'esbuild-plugin-inline-image'
|
2023-03-31 17:19:07 +03:00
|
|
|
import esbuildPluginTime from 'esbuild-plugin-time'
|
2023-05-02 20:48:07 +03:00
|
|
|
import esbuildPluginYaml from 'esbuild-plugin-yaml'
|
2023-03-31 17:19:07 +03:00
|
|
|
import postcss from 'postcss'
|
|
|
|
import tailwindcss from 'tailwindcss'
|
2024-07-05 14:13:04 +03:00
|
|
|
import tailwindcssNesting from 'tailwindcss/nesting'
|
2023-03-31 17:19:07 +03:00
|
|
|
|
2024-03-08 06:14:26 +03:00
|
|
|
import * as appConfig from 'enso-common/src/appConfig'
|
|
|
|
import * as buildUtils from 'enso-common/src/buildUtils'
|
|
|
|
|
2024-01-10 19:22:11 +03:00
|
|
|
import * as tailwindConfig from './tailwind.config'
|
2023-03-31 17:19:07 +03:00
|
|
|
|
|
|
|
// =================
|
|
|
|
// === Constants ===
|
|
|
|
// =================
|
|
|
|
|
|
|
|
const THIS_PATH = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)))
|
|
|
|
|
2024-03-08 06:14:26 +03:00
|
|
|
// ====================
|
|
|
|
// === Global setup ===
|
|
|
|
// ====================
|
|
|
|
|
|
|
|
await appConfig.readEnvironmentFromFile()
|
|
|
|
|
2023-03-31 17:19:07 +03:00
|
|
|
// =============================
|
|
|
|
// === Environment variables ===
|
|
|
|
// =============================
|
|
|
|
|
2023-05-19 22:55:29 +03:00
|
|
|
/** Mandatory build options. */
|
2023-03-31 17:19:07 +03:00
|
|
|
export interface Arguments {
|
|
|
|
/** Path where bundled files are output. */
|
2024-02-07 14:26:59 +03:00
|
|
|
readonly outputPath: string
|
2023-03-31 17:19:07 +03:00
|
|
|
}
|
|
|
|
|
2023-05-19 22:55:29 +03:00
|
|
|
/** Get arguments from the environment. */
|
2023-03-31 17:19:07 +03:00
|
|
|
export function argumentsFromEnv(): Arguments {
|
2024-03-08 06:14:26 +03:00
|
|
|
const outputPath = path.resolve(buildUtils.requireEnv('ENSO_BUILD_GUI'), 'assets')
|
|
|
|
return { outputPath }
|
2023-03-31 17:19:07 +03:00
|
|
|
}
|
|
|
|
|
2023-05-19 22:55:29 +03:00
|
|
|
// =======================
|
|
|
|
// === Esbuild plugins ===
|
|
|
|
// =======================
|
2023-03-31 17:19:07 +03:00
|
|
|
|
2023-05-19 22:55:29 +03:00
|
|
|
/** A plugin to process all CSS files with Tailwind CSS. */
|
2023-09-22 06:43:25 +03:00
|
|
|
export function esbuildPluginGenerateTailwind(): esbuild.Plugin {
|
2023-03-31 17:19:07 +03:00
|
|
|
return {
|
|
|
|
name: 'enso-generate-tailwind',
|
|
|
|
setup: build => {
|
2023-11-29 20:29:25 +03:00
|
|
|
const cssProcessor = postcss(
|
2023-03-31 17:19:07 +03:00
|
|
|
tailwindcss({
|
2023-11-29 20:29:25 +03:00
|
|
|
...tailwindConfig.default,
|
|
|
|
content: tailwindConfig.default.content.map(glob =>
|
|
|
|
glob.replace(/^[.][/]/, THIS_PATH + '/')
|
|
|
|
),
|
2023-03-31 17:19:07 +03:00
|
|
|
}),
|
2023-11-29 20:29:25 +03:00
|
|
|
tailwindcssNesting()
|
|
|
|
)
|
2023-07-24 22:58:53 +03:00
|
|
|
build.onLoad({ filter: /tailwind\.css$/ }, async loadArgs => {
|
2023-08-31 18:03:39 +03:00
|
|
|
const content = await fs.readFile(loadArgs.path, 'utf8')
|
2024-01-10 19:22:11 +03:00
|
|
|
const result = await cssProcessor.process(content, {
|
|
|
|
from: loadArgs.path,
|
|
|
|
})
|
2023-03-31 17:19:07 +03:00
|
|
|
return {
|
2023-08-31 18:03:39 +03:00
|
|
|
contents: result.content,
|
2023-03-31 17:19:07 +03:00
|
|
|
loader: 'css',
|
2023-09-22 06:43:25 +03:00
|
|
|
watchFiles: [loadArgs.path],
|
2023-03-31 17:19:07 +03:00
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ================
|
|
|
|
// === Bundling ===
|
|
|
|
// ================
|
|
|
|
|
|
|
|
/** Generate the bundler options. */
|
|
|
|
export function bundlerOptions(args: Arguments) {
|
2024-03-08 06:14:26 +03:00
|
|
|
const { outputPath } = args
|
2023-06-19 02:02:08 +03:00
|
|
|
// This is required to prevent TypeScript from narrowing `true` to `boolean`.
|
|
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
|
|
const trueBoolean = true as boolean
|
2023-03-31 17:19:07 +03:00
|
|
|
const buildOptions = {
|
|
|
|
absWorkingDir: THIS_PATH,
|
2023-06-19 02:02:08 +03:00
|
|
|
bundle: trueBoolean,
|
2023-03-31 17:19:07 +03:00
|
|
|
entryPoints: [path.resolve(THIS_PATH, 'src', 'tailwind.css')],
|
|
|
|
outdir: outputPath,
|
|
|
|
outbase: 'src',
|
2023-06-23 11:47:04 +03:00
|
|
|
loader: {
|
2023-07-27 11:53:00 +03:00
|
|
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
|
|
// The `file` loader copies the file, and replaces the import with the path to the file.
|
|
|
|
'.png': 'file',
|
2023-10-29 22:02:07 +03:00
|
|
|
'.jpg': 'file',
|
2023-07-27 11:53:00 +03:00
|
|
|
/* eslint-enable @typescript-eslint/naming-convention */
|
2023-06-23 11:47:04 +03:00
|
|
|
},
|
2023-03-31 17:19:07 +03:00
|
|
|
plugins: [
|
2023-09-22 06:43:25 +03:00
|
|
|
// The CSS file needs to import a single SVG as a data URL.
|
|
|
|
// For `bundle.ts` and `watch.ts`, `index.js` also includes various SVG icons
|
|
|
|
// which need to be bundled.
|
|
|
|
// Depending on file size, choose between `dataurl` and `file` loaders.
|
|
|
|
// The `dataurl` loader replaces the import with the file, as a data URL. Using the
|
|
|
|
// `file` loader, which copies the file and replaces the import with the path.
|
|
|
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
|
|
esbuildPluginInlineImage({ extensions: ['svg'] }),
|
2023-03-31 17:19:07 +03:00
|
|
|
esbuildPluginNodeModules.NodeModulesPolyfillPlugin(),
|
|
|
|
esbuildPluginTime(),
|
2023-05-19 22:55:29 +03:00
|
|
|
// This is not strictly needed because the cloud frontend does not use
|
|
|
|
// the Project Manager, however it is very difficult to conditionally exclude a module.
|
2023-05-02 20:48:07 +03:00
|
|
|
esbuildPluginYaml.yamlPlugin({}),
|
2023-03-31 17:19:07 +03:00
|
|
|
esbuildPluginGenerateTailwind(),
|
|
|
|
],
|
2024-01-10 19:22:11 +03:00
|
|
|
alias: {
|
|
|
|
'#': './src',
|
|
|
|
},
|
2024-03-08 06:14:26 +03:00
|
|
|
define: appConfig.getDefines(),
|
2023-06-19 02:02:08 +03:00
|
|
|
pure: ['assert'],
|
2023-09-22 06:43:25 +03:00
|
|
|
sourcemap: true,
|
2023-06-19 02:02:08 +03:00
|
|
|
metafile: trueBoolean,
|
2023-03-31 17:19:07 +03:00
|
|
|
format: 'esm',
|
|
|
|
platform: 'browser',
|
2023-06-19 02:02:08 +03:00
|
|
|
color: trueBoolean,
|
2023-03-31 17:19:07 +03:00
|
|
|
} satisfies esbuild.BuildOptions
|
|
|
|
// The narrower type is required to avoid non-null assertions elsewhere.
|
2023-04-11 09:04:27 +03:00
|
|
|
// The intersection with `esbuild.BuildOptions` is required to allow adding extra properties.
|
2023-03-31 17:19:07 +03:00
|
|
|
const correctlyTypedBuildOptions: esbuild.BuildOptions & typeof buildOptions = buildOptions
|
|
|
|
return correctlyTypedBuildOptions
|
|
|
|
}
|
|
|
|
|
2023-05-19 22:55:29 +03:00
|
|
|
/** esbuild options for bundling (one-off build) the package.
|
2023-03-31 17:19:07 +03:00
|
|
|
*
|
|
|
|
* Relies on the environment variables to be set. */
|
|
|
|
export function bundleOptions() {
|
|
|
|
return bundlerOptions(argumentsFromEnv())
|
|
|
|
}
|