-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathrollup.config.mjs
More file actions
106 lines (101 loc) · 3.29 KB
/
Copy pathrollup.config.mjs
File metadata and controls
106 lines (101 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { copyFileSync, mkdirSync, existsSync, readdirSync, statSync } from 'fs';
import { resolve, dirname, relative } from 'path';
import cleanup from 'rollup-plugin-cleanup';
import typescript from '@rollup/plugin-typescript';
import json from '@rollup/plugin-json';
import Oxc from 'unplugin-oxc/rollup';
import pkg from './package.json' with { type: 'json' };
const DATA_DIR = resolve('data');
/**
* Rollup plugin that keeps JSON files from data/ as separate files in dist/
* instead of inlining them as JS object literals.
*
* Without this, @rollup/plugin-json converts large dictionaries (e.g. the
* 2.8 MB English pronunciation dictionary) into JavaScript source code.
* Hermes (React Native's JS engine) cannot compile such large files to
* bytecode, crashing with "Error encoding bytecode".
*
* Keeping them as .json means bundlers like Metro load them natively
* without bytecode compilation.
*/
function externalDataPlugin() {
return {
name: 'external-data',
resolveId(source, importer) {
if (!importer) return null;
const resolved = resolve(dirname(importer), source);
if (resolved.startsWith(DATA_DIR) && resolved.endsWith('.json')) {
return { id: './' + relative(DATA_DIR, resolved), external: true };
}
return null;
},
writeBundle() {
copyDirRecursive(DATA_DIR, resolve('dist'));
},
};
}
// JSON files in data/ that are BUILD-TIME ONLY and should not ship to
// dist/. The legacy 2.7 MB English dict is no longer loaded at runtime
// (en-g2p.ts uses data/en/exceptions.json instead); alignment artifacts
// are inputs to scripts/compile-lts.ts and not needed by the runtime.
const BUILD_ONLY_DATA = new Set([
'en/dict.json',
'en/alignments.json',
'en/align-stats.json',
'en/exception-candidates.json',
]);
function copyDirRecursive(src, dest) {
if (!existsSync(src)) return;
for (const entry of readdirSync(src)) {
const srcPath = resolve(src, entry);
const destPath = resolve(dest, entry);
if (statSync(srcPath).isDirectory()) {
copyDirRecursive(srcPath, destPath);
} else if (entry.endsWith('.json')) {
const relPath = relative(DATA_DIR, srcPath);
if (BUILD_ONLY_DATA.has(relPath)) continue;
mkdirSync(dirname(destPath), { recursive: true });
copyFileSync(srcPath, destPath);
}
}
}
export default {
// Map each public export to its source entry. Language G2P entries live
// under src/<lang>/g2p.ts; the public name stays "<lang>-g2p" (= the output
// chunk name), everything else is a flat src/<name>.ts.
input: Object.fromEntries(
Object.keys(pkg.exports).map((name) => {
const key = name.replace(/^\.\/?/, '') || 'index';
const lang = key.match(/^([a-z]+)-g2p$/);
return [key, lang ? `src/${lang[1]}/g2p.ts` : `src/${key}.ts`];
}),
),
output: [
{
dir: 'dist',
entryFileNames: '[name].cjs',
chunkFileNames: '[name]-[hash].cjs',
format: 'cjs',
},
{
dir: 'dist',
entryFileNames: '[name].mjs',
chunkFileNames: '[name]-[hash].mjs',
format: 'es',
},
],
plugins: [
externalDataPlugin(),
cleanup({ extensions: ['cjs', 'mjs', 'd.ts'] }),
typescript(),
json({
compact: true,
preferConst: true,
}),
Oxc({
minify: {
sourceMap: false,
}
}),
],
};