You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-23 22:36:32 +02:00
142 lines
5.2 KiB
TypeScript
142 lines
5.2 KiB
TypeScript
import { filename, toForwardSlashes } from '@joplin/utils/path';
|
|
import * as esbuild from 'esbuild';
|
|
import { existsSync, readFileSync } from 'fs';
|
|
import { writeFile } from 'fs/promises';
|
|
import { dirname, join, relative } from 'path';
|
|
|
|
const baseDir = dirname(__dirname);
|
|
const baseNodeModules = join(baseDir, 'node_modules');
|
|
|
|
// Note: Roughly based on js-draw's use of esbuild:
|
|
// https://github.com/personalizedrefrigerator/js-draw/blob/6fe6d6821402a08a8d17f15a8f48d95e5d7b084f/packages/build-tool/src/BundledFile.ts#L64
|
|
const makeBuildContext = (entryPoint: string, renderer: boolean, addDebugStats: boolean) => {
|
|
return esbuild.context({
|
|
entryPoints: [entryPoint],
|
|
outfile: `${filename(entryPoint)}.bundle.js`,
|
|
bundle: true,
|
|
minify: true,
|
|
keepNames: true, // Preserve original function names -- useful for debugging
|
|
format: 'iife', // Immediately invoked function expression
|
|
sourcemap: true,
|
|
sourcesContent: false, // Do not embed full source file content in the .map file
|
|
metafile: addDebugStats,
|
|
platform: 'node',
|
|
target: ['node20.0'],
|
|
mainFields: renderer ? ['browser', 'main'] : ['main'],
|
|
plugins: [
|
|
{
|
|
// Configures ESBuild to require(...) certain libraries that cause issues if included directly
|
|
// in the bundle. Some of these are transitive dependencies and so need to have relative paths
|
|
// in the final bundle.
|
|
name: 'joplin--relative-imports-for-externals',
|
|
setup: build => {
|
|
const externalRegex = /^(.*\.node|sqlite3|node-fetch|electron|@electron\/remote\/.*|electron\/.*|@mapbox\/node-pre-gyp|jsdom)$/;
|
|
build.onResolve({ filter: externalRegex }, args => {
|
|
// Electron packages don't need relative requires
|
|
if (args.path === 'electron' || args.path.startsWith('electron/')) {
|
|
return { path: args.path, external: true, namespace: 'node' };
|
|
}
|
|
|
|
// Other packages may need relative requires
|
|
let path = toForwardSlashes(relative(
|
|
baseDir,
|
|
require.resolve(args.path, { paths: [baseNodeModules, args.resolveDir, baseDir] }),
|
|
));
|
|
if (!path.startsWith('.')) {
|
|
path = `./${path}`;
|
|
}
|
|
|
|
// Some files have .node.* extensions but are not native modules. These files are often required using
|
|
// require('./something.node') rather than require('./something.node.js'). Skip path remapping for
|
|
// these files:
|
|
if (args.path.endsWith('.node') && (path.endsWith('.ts') || path.endsWith('.js'))) {
|
|
// Normal .ts or .js file -- continue.
|
|
return null;
|
|
}
|
|
|
|
// Log that this is external -- it should be included in "dependencies" and not "devDependencies" in package.json:
|
|
console.log('External path:', path, args.importer);
|
|
return {
|
|
path,
|
|
external: true,
|
|
};
|
|
});
|
|
},
|
|
},
|
|
{
|
|
// Rewrite imports to prefer .js files to .ts. Otherwise, certain files are duplicated in the final bundle
|
|
name: 'joplin--prefer-js-imports',
|
|
setup: build => {
|
|
// Rewrite all relative imports
|
|
build.onResolve({ filter: /^\./ }, args => {
|
|
try {
|
|
const importPath = args.path === '.' ? './index' : args.path;
|
|
let path = require.resolve(importPath, { paths: [args.resolveDir, baseNodeModules, baseDir] });
|
|
// require.resolve **can** return paths with .ts extensions, presumably because
|
|
// this build script is a .ts file.
|
|
if (path.endsWith('.ts')) {
|
|
const alternative = path.replace(/\.ts$/, '.js');
|
|
if (existsSync(alternative)) {
|
|
path = alternative;
|
|
}
|
|
}
|
|
return { path };
|
|
} catch (error) {
|
|
return {
|
|
errors: [{ text: `Failed to import: ${error}`, detail: error }],
|
|
};
|
|
}
|
|
});
|
|
},
|
|
},
|
|
{
|
|
name: 'joplin--smaller-source-map-size',
|
|
setup: build => {
|
|
// Unless bundling with additional debug information, exclude 3rd-party
|
|
// dependencies from source maps. This significantly reduces the size of the
|
|
// source map, improving startup performance.
|
|
//
|
|
// See https://github.com/evanw/esbuild/issues/1685#issuecomment-944916409
|
|
// and https://github.com/evanw/esbuild/issues/4130
|
|
if (!addDebugStats) {
|
|
const emptyMapData = Buffer.from(
|
|
JSON.stringify({ version: 3, sources: [null], mappings: 'AAAA' }),
|
|
'utf-8',
|
|
).toString('base64');
|
|
const emptyMapUrl = `data:application/json;base64,${emptyMapData}`;
|
|
|
|
build.onLoad({ filter: /node_modules.*js$/ }, args => {
|
|
return {
|
|
contents: [
|
|
readFileSync(args.path, 'utf8'),
|
|
`//# sourceMappingURL=${emptyMapUrl}`,
|
|
].join('\n'),
|
|
loader: 'default',
|
|
};
|
|
});
|
|
}
|
|
},
|
|
},
|
|
],
|
|
});
|
|
};
|
|
|
|
const bundleJs = async (writeStats: boolean) => {
|
|
const entryPoints = [
|
|
{ fileName: 'main.ts', renderer: false },
|
|
{ fileName: 'main-html.ts', renderer: true },
|
|
];
|
|
for (const { fileName, renderer } of entryPoints) {
|
|
const compiler = await makeBuildContext(fileName, renderer, writeStats);
|
|
const result = await compiler.rebuild();
|
|
if (writeStats) {
|
|
const outPath = `${dirname(__dirname)}/${fileName}.meta.json`;
|
|
console.log('Writing bundle stats to ', outPath);
|
|
await writeFile(outPath, JSON.stringify(result.metafile, undefined, '\t'));
|
|
}
|
|
await compiler.dispose();
|
|
}
|
|
};
|
|
|
|
export default bundleJs;
|