Repository navigation
Expand file tree
/
Copy pathvite.config.js
More file actions
102 lines (102 loc) · 4.62 KB
/
Copy pathvite.config.js
File metadata and controls
102 lines (102 loc) · 4.62 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
import { defineConfig } from 'vite';
import { cpSync, mkdirSync } from 'node:fs';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import puterLocalhost from '../../dev/puter-localhost.mjs';
let workerDevelopmentUrl;
// On-device OCR (src/ocr-engine.js) loads tesseract.js's worker, its WebAssembly core and the
// English model from ocr/ beside the app, never from a CDN. Only the LSTM cores are needed (the
// engine runs LSTM-only); the worker picks one by the browser's SIMD support. The model is
// tessdata_best_int (integer-quantized "best"), a good balance of size and accuracy.
const ocrAssets = {
'worker.min.js': 'node_modules/tesseract.js/dist/worker.min.js',
'core/tesseract-core-relaxedsimd-lstm.wasm.js':
'node_modules/tesseract.js-core/tesseract-core-relaxedsimd-lstm.wasm.js',
'core/tesseract-core-simd-lstm.wasm.js':
'node_modules/tesseract.js-core/tesseract-core-simd-lstm.wasm.js',
'core/tesseract-core-lstm.wasm.js': 'node_modules/tesseract.js-core/tesseract-core-lstm.wasm.js',
'lang/eng.traineddata.gz':
'node_modules/@tesseract.js-data/eng/4.0.0_best_int/eng.traineddata.gz',
'LICENSE-tesseract.js.md': 'node_modules/tesseract.js/LICENSE.md',
'LICENSE-tesseract.js-core.txt': 'node_modules/tesseract.js-core/LICENSE',
};
export default defineConfig({
base: './',
plugins: [
puterLocalhost('pdf'),
{
// Keep the worker's module export: PDF.js imports WorkerMessageHandler on the main
// thread when native workers are unavailable. Vite's ?worker bundles drop exports.
name: 'pdf-worker-entry',
configResolved(config) {
workerDevelopmentUrl = `${config.base}src/pdf-worker.js`;
},
resolveId(id) {
if (id === 'virtual:pdf-worker-url') return '\0pdf-worker-url';
},
load(id) {
if (id !== '\0pdf-worker-url') return;
if (this.environment.mode === 'dev')
return `export default ${JSON.stringify(workerDevelopmentUrl)}`;
const ref = this.emitFile({
type: 'chunk',
id: fileURLToPath(new URL('./src/pdf-worker.js', import.meta.url)),
preserveSignature: 'strict',
});
return `export default import.meta.ROLLUP_FILE_URL_${ref}`;
},
},
{
name: 'pdf-assets',
closeBundle() {
for (const dir of ['cmaps', 'standard_fonts', 'wasm', 'iccs']) {
mkdirSync(`dist/pdfjs/${dir}`, { recursive: true });
cpSync(`node_modules/pdfjs-dist/${dir}`, `dist/pdfjs/${dir}`, { recursive: true });
}
// Four of the standard fonts are Liberation Sans 1.07.4, licensed under the GPL v2 with
// a font exception, so the build ships their corresponding source and license beside
// them (see vendor/liberation-fonts and docs/ENGINE_AND_LICENSES.md).
cpSync('vendor/liberation-fonts', 'dist/pdfjs/standard_fonts/liberation-source', {
recursive: true,
});
},
configureServer(server) {
server.middlewares.use('/pdfjs', async (req, res, next) => {
const { createReadStream, existsSync } = await import('node:fs');
const { resolve, sep } = await import('node:path');
const root = resolve('node_modules/pdfjs-dist');
const path = resolve(root, '.' + (req.url || '').split('?')[0]);
if (!path.startsWith(root + sep) || !existsSync(path)) return next();
if (path.endsWith('.wasm')) res.setHeader('Content-Type', 'application/wasm');
createReadStream(path).on('error', next).pipe(res);
});
},
},
{
name: 'ocr-assets',
closeBundle() {
for (const [to, from] of Object.entries(ocrAssets)) {
mkdirSync(dirname(`dist/ocr/${to}`), { recursive: true });
cpSync(from, `dist/ocr/${to}`);
}
},
configureServer(server) {
server.middlewares.use('/ocr', async (req, res, next) => {
const { createReadStream } = await import('node:fs');
const from = ocrAssets[decodeURIComponent((req.url || '').split('?')[0]).slice(1)];
if (!from) return next();
// The model stays gzip-compressed on the wire; tesseract.js inflates it itself.
const type = from.endsWith('.gz')
? 'application/octet-stream'
: from.endsWith('.js')
? 'text/javascript'
: 'text/plain';
res.setHeader('Content-Type', type);
createReadStream(from).on('error', next).pipe(res);
});
},
},
],
// Tests that render through PDF.js need longer than the default five seconds on a busy machine.
test: { include: ['tests/**/*.test.js'], testTimeout: 20000 },
});