feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
@@ -0,0 +1,184 @@
|
||||
import { filename, toForwardSlashes } from '@joplin/utils/path';
|
||||
import * as esbuild from 'esbuild';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
import { dirname, join, relative } from 'path';
|
||||
|
||||
const baseDir = dirname(__dirname);
|
||||
const baseNodeModules = join(baseDir, 'node_modules');
|
||||
|
||||
const undiciPath = join(__dirname, '../build/undici.bundle.js');
|
||||
|
||||
// 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, overrides?: Partial<esbuild.BuildOptions>) => {
|
||||
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'],
|
||||
...overrides,
|
||||
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|onnxruntime-node|@xenova\/transformers)$/;
|
||||
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',
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'joplin--fix-undici',
|
||||
setup: build => {
|
||||
build.onResolve({ filter: /^undici$/ }, () => {
|
||||
return {
|
||||
path: undiciPath,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
...(overrides?.plugins ?? []),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const bundleUndici = async () => {
|
||||
// By default, Undici is broken in Electron renderer environments and can cause renderer process
|
||||
// crashes when fetching certain URLs.
|
||||
//
|
||||
// Undici relies on several NodeJS global objects that are replaced in the Electron renderer process.
|
||||
// For example, with the Electron globals, there's no .unref() on timer handles returned by setTimeout().
|
||||
//
|
||||
// As a workaround, add imports for many of the built-in objects so that Undici uses the NodeJS versions
|
||||
// of the built-ins:
|
||||
const undiciBuilder = await makeBuildContext(
|
||||
require.resolve('undici'), true, false, { outfile: undiciPath, format: 'cjs', sourcemap: false, minify: false },
|
||||
);
|
||||
await undiciBuilder.rebuild();
|
||||
await writeFile(undiciPath, `
|
||||
const { Buffer, Blob, File } = require('node:buffer');
|
||||
const { TextDecoder, TextEncoder } = require('node:util');
|
||||
const { URLSearchParams, URL } = require('node:url');
|
||||
const { ReadableStream } = require('node:stream/web');
|
||||
const { MessageChannel, MessagePort } = require('node:worker_threads');
|
||||
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('node:timers');
|
||||
const { performance } = require('node:perf_hooks');
|
||||
|
||||
${await readFile(undiciPath, 'utf-8')}
|
||||
`, 'utf-8');
|
||||
await undiciBuilder.dispose();
|
||||
};
|
||||
|
||||
const bundleJs = async (writeStats: boolean) => {
|
||||
await bundleUndici();
|
||||
|
||||
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;
|
||||
在新工单中引用
屏蔽一个用户