diff --git a/.esbuild/build.ts b/.esbuild/build.ts new file mode 100644 index 000000000..d5adf070b --- /dev/null +++ b/.esbuild/build.ts @@ -0,0 +1,31 @@ +import { build } from 'esbuild'; +import { getBuildConfig, packageOptions } from './util.js'; +import { context } from 'esbuild'; + +const shouldWatch = process.argv.includes('--watch'); + +const buildPackage = async (entryName: keyof typeof packageOptions) => { + await build(getBuildConfig({ entryName, minify: false })); + await build(getBuildConfig({ entryName, minify: true })); + await build(getBuildConfig({ entryName, minify: false, core: true })); +}; + +const handler = (e) => { + console.error(e); + process.exit(1); +}; + +const main = async () => { + const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[]; + for (const pkg of packageNames) { + await buildPackage(pkg).catch(handler); + } +}; + +const watch = async () => { + const ctx = await context(getBuildConfig({ entryName: 'mermaid', minify: false })); + ctx.watch(); + console.log('Watching for changes'); +}; + +void (shouldWatch ? watch : main)(); diff --git a/.vite/jisonTransformer.ts b/.esbuild/jisonTransformer.ts similarity index 100% rename from .vite/jisonTransformer.ts rename to .esbuild/jisonTransformer.ts diff --git a/.vite/server.ts b/.esbuild/server.ts similarity index 54% rename from .vite/server.ts rename to .esbuild/server.ts index 7a65cba00..3ef78cf6b 100644 --- a/.vite/server.ts +++ b/.esbuild/server.ts @@ -1,23 +1,21 @@ import express from 'express'; import cors from 'cors'; -import { createServer as createViteServer } from 'vite'; +import proxy from 'express-http-proxy'; +import { getBuildConfig } from './util.js'; +import { context } from 'esbuild'; async function createServer() { const app = express(); - - // Create Vite server in middleware mode - const vite = await createViteServer({ - configFile: './vite.config.ts', - server: { middlewareMode: true }, - appType: 'custom', // don't include Vite's default HTML handling middlewares - }); - + const config = getBuildConfig({ minify: false, core: false, entryName: 'mermaid' }); + const ctx = await context(config); + ctx.watch(); + let { host, port } = await ctx.serve({ servedir: './dist' }); app.use(cors()); app.use(express.static('./packages/mermaid/dist')); app.use(express.static('./packages/mermaid-example-diagram/dist')); - app.use(vite.middlewares); app.use(express.static('demos')); app.use(express.static('cypress/platform')); + app.use('/', proxy(`http://${host}:${port}`)); app.listen(9000, () => { console.log(`Listening on http://localhost:9000`); diff --git a/.esbuild/util.ts b/.esbuild/util.ts new file mode 100644 index 000000000..dd8114bbd --- /dev/null +++ b/.esbuild/util.ts @@ -0,0 +1,89 @@ +import { resolve } from 'path'; +import { fileURLToPath } from 'url'; +import { BuildOptions } from 'esbuild'; +import { readFileSync } from 'fs'; +import { readFile } from 'fs/promises'; +import { transformJison } from './jisonTransformer.js'; + +const __dirname = fileURLToPath(new URL('.', import.meta.url)); + +export const packageOptions = { + mermaid: { + name: 'mermaid', + packageName: 'mermaid', + file: 'mermaid.ts', + }, + 'mermaid-example-diagram': { + name: 'mermaid-example-diagram', + packageName: 'mermaid-example-diagram', + file: 'detector.ts', + }, +}; + +interface MermaidBuildOptions { + minify: boolean; + core?: boolean; + entryName: keyof typeof packageOptions; +} + +const buildOptions = (override: BuildOptions): BuildOptions => { + return { + bundle: true, + splitting: true, + minify: true, + keepNames: true, + banner: { js: '"use strict";' }, + format: 'esm', + platform: 'browser', + tsconfig: 'tsconfig.json', + resolveExtensions: ['.ts', '.js', '.json', '.jison'], + external: ['require', 'fs', 'path'], + outdir: 'dist', + plugins: [jisonPlugin], + sourcemap: 'external', + outExtension: { '.js': '.mjs' }, + ...override, + }; +}; + +const jisonPlugin = { + name: 'jison', + setup(build) { + build.onLoad({ filter: /\.jison$/ }, async (args) => { + // Load the file from the file system + const source = await readFile(args.path, 'utf8'); + const contents = transformJison(source); + return { contents, warnings: [] }; + }); + }, +}; + +export const getBuildConfig = ({ minify, core, entryName }: MermaidBuildOptions): BuildOptions => { + const external: string[] = ['require', 'fs', 'path']; + const { name, file, packageName } = packageOptions[entryName]; + let output: BuildOptions = buildOptions({ + absWorkingDir: resolve(__dirname, `../packages/${packageName}`), + entryPoints: { + [`${name}.esm${core ? '.core' : ''}${minify ? '.min' : ''}`]: `src/${file}`, + }, + }); + + if (core) { + const { dependencies } = JSON.parse( + readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8') + ); + // Core build is used to generate file without bundled dependencies. + // This is used by downstream projects to bundle dependencies themselves. + // Ignore dependencies and any dependencies of dependencies + external.push(...Object.keys(dependencies)); + output.external = external; + } + + // if (watch && config.build) { + // config.build.watch = { + // include: ['packages/mermaid-example-diagram/src/**', 'packages/mermaid/src/**'], + // }; + // } + + return output; +}; diff --git a/.vite/build.ts b/.vite/build.ts deleted file mode 100644 index 268db3270..000000000 --- a/.vite/build.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { build, InlineConfig, type PluginOption } from 'vite'; -import { resolve } from 'path'; -import { fileURLToPath } from 'url'; -import jisonPlugin from './jisonPlugin.js'; -import { readFileSync } from 'fs'; -import { visualizer } from 'rollup-plugin-visualizer'; -import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types.js'; - -const visualize = process.argv.includes('--visualize'); -const watch = process.argv.includes('--watch'); -const mermaidOnly = process.argv.includes('--mermaid'); -const __dirname = fileURLToPath(new URL('.', import.meta.url)); - -type OutputOptions = Exclude< - Exclude['rollupOptions'], - undefined ->['output']; - -const visualizerOptions = (packageName: string, core = false): PluginOption[] => { - if (packageName !== 'mermaid' || !visualize) { - return []; - } - return ['network', 'treemap', 'sunburst'].map( - (chartType) => - visualizer({ - filename: `./stats/${chartType}${core ? '.core' : ''}.html`, - template: chartType as TemplateType, - gzipSize: true, - brotliSize: true, - }) as PluginOption - ); -}; - -const packageOptions = { - mermaid: { - name: 'mermaid', - packageName: 'mermaid', - file: 'mermaid.ts', - }, - 'mermaid-example-diagram': { - name: 'mermaid-example-diagram', - packageName: 'mermaid-example-diagram', - file: 'detector.ts', - }, -}; - -interface BuildOptions { - minify: boolean | 'esbuild'; - core?: boolean; - watch?: boolean; - entryName: keyof typeof packageOptions; -} - -export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions): InlineConfig => { - const external: (string | RegExp)[] = ['require', 'fs', 'path']; - console.log(entryName, packageOptions[entryName]); - const { name, file, packageName } = packageOptions[entryName]; - let output: OutputOptions = [ - { - name, - format: 'esm', - sourcemap: true, - entryFileNames: `${name}.esm${minify ? '.min' : ''}.mjs`, - }, - ]; - - if (core) { - const { dependencies } = JSON.parse( - readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8') - ); - // Core build is used to generate file without bundled dependencies. - // This is used by downstream projects to bundle dependencies themselves. - // Ignore dependencies and any dependencies of dependencies - // Adapted from the RegEx used by `rollup-plugin-node` - external.push(new RegExp('^(?:' + Object.keys(dependencies).join('|') + ')(?:/.+)?$')); - // This needs to be an array. Otherwise vite will build esm & umd with same name and overwrite esm with umd. - output = [ - { - name, - format: 'esm', - sourcemap: true, - entryFileNames: `${name}.core.mjs`, - }, - ]; - } - - const config: InlineConfig = { - configFile: false, - build: { - emptyOutDir: false, - outDir: resolve(__dirname, `../packages/${packageName}/dist`), - lib: { - entry: resolve(__dirname, `../packages/${packageName}/src/${file}`), - name, - // the proper extensions will be added - fileName: name, - }, - minify, - rollupOptions: { - external, - output, - }, - }, - resolve: { - extensions: ['.jison', '.js', '.ts', '.json'], - }, - plugins: [jisonPlugin(), ...visualizerOptions(packageName, core)], - }; - - if (watch && config.build) { - config.build.watch = { - include: ['packages/mermaid-example-diagram/src/**', 'packages/mermaid/src/**'], - }; - } - - return config; -}; - -const buildPackage = async (entryName: keyof typeof packageOptions) => { - await build(getBuildConfig({ minify: false, entryName })); - await build(getBuildConfig({ minify: 'esbuild', entryName })); - await build(getBuildConfig({ minify: false, core: true, entryName })); -}; - -const main = async () => { - const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[]; - for (const pkg of packageNames.filter((pkg) => !mermaidOnly || pkg === 'mermaid')) { - await buildPackage(pkg); - } -}; - -if (watch) { - build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' })); - if (!mermaidOnly) { - build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' })); - } -} else if (visualize) { - await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' })); - await build(getBuildConfig({ minify: false, core: false, entryName: 'mermaid' })); -} else { - void main(); -} diff --git a/.vite/jisonPlugin.ts b/.vite/jisonPlugin.ts index c21190784..8da95800f 100644 --- a/.vite/jisonPlugin.ts +++ b/.vite/jisonPlugin.ts @@ -1,4 +1,4 @@ -import { transformJison } from './jisonTransformer.js'; +import { transformJison } from '../.esbuild/jisonTransformer.js'; const fileRegex = /\.(jison)$/; export default function jison() { diff --git a/cypress/platform/ashish2.html b/cypress/platform/ashish2.html index bcea4f4cc..76fbd36f7 100644 --- a/cypress/platform/ashish2.html +++ b/cypress/platform/ashish2.html @@ -188,7 +188,7 @@ mindmap //import mindmap from '../../packages/mermaid-mindmap/src/detector'; // import example from '../../packages/mermaid-example-diagram/src/detector'; // import timeline from '../../packages/mermaid-timeline/src/detector'; - import mermaid from '../../packages/mermaid/src/mermaid'; + import mermaid from './mermaid.esm.mjs'; // await mermaid.registerExternalDiagrams([]); mermaid.parseError = function (err, hash) { // console.error('Mermaid error: ', err); diff --git a/cypress/platform/external-diagrams-example-diagram.html b/cypress/platform/external-diagrams-example-diagram.html index b5b716ff8..87d6ad4be 100644 --- a/cypress/platform/external-diagrams-example-diagram.html +++ b/cypress/platform/external-diagrams-example-diagram.html @@ -13,7 +13,7 @@ example-diagram