241 lines
6.3 KiB
JavaScript
241 lines
6.3 KiB
JavaScript
import { cp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const frontendDir = path.resolve(
|
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
'..',
|
|
);
|
|
const rootDir = path.resolve(frontendDir, '../..');
|
|
const publicDir = path.join(frontendDir, 'public');
|
|
|
|
function resolvePackage(...parts) {
|
|
const candidates = [
|
|
path.join(frontendDir, 'node_modules', ...parts),
|
|
path.join(rootDir, 'node_modules', ...parts),
|
|
];
|
|
return candidates;
|
|
}
|
|
|
|
async function copyFirst(sources, destination) {
|
|
const output = path.join(publicDir, destination);
|
|
await mkdir(path.dirname(output), { recursive: true });
|
|
let lastError;
|
|
for (const source of sources) {
|
|
try {
|
|
await cp(source, output);
|
|
return output;
|
|
} catch (error) {
|
|
lastError = error;
|
|
}
|
|
}
|
|
throw lastError ?? new Error(`Missing asset for ${destination}`);
|
|
}
|
|
|
|
const cadAssets = [
|
|
[
|
|
resolvePackage('@mlightcad/cad-simple-viewer/dist/dxf-parser-worker.js'),
|
|
'assets/dxf-parser-worker.js',
|
|
],
|
|
[
|
|
resolvePackage(
|
|
'@mlightcad/cad-simple-viewer/dist/libredwg-parser-worker.js',
|
|
),
|
|
'assets/libredwg-parser-worker.js',
|
|
],
|
|
[
|
|
resolvePackage(
|
|
'@mlightcad/cad-simple-viewer/dist/mtext-renderer-worker.js',
|
|
),
|
|
'assets/mtext-renderer-worker.js',
|
|
],
|
|
[
|
|
resolvePackage('@noto-pdf-ts/fonts-kr/dist/fonts/NotoSansKR-VF.ttf'),
|
|
'viewer-assets/cad-resources/fonts/NotoSansKR-VF.ttf',
|
|
],
|
|
[
|
|
resolvePackage('@fontsource-variable/noto-sans-kr/LICENSE'),
|
|
'viewer-assets/cad-resources/fonts/OFL-1.1.txt',
|
|
],
|
|
];
|
|
|
|
const o3dvAssets = [
|
|
[
|
|
resolvePackage('rhino3dm/rhino3dm.min.js'),
|
|
'viewer-assets/o3dv/rhino3dm.min.js',
|
|
],
|
|
[
|
|
resolvePackage('rhino3dm/rhino3dm.wasm'),
|
|
'viewer-assets/o3dv/rhino3dm.wasm',
|
|
],
|
|
[
|
|
resolvePackage('web-ifc/web-ifc-api-iife.js'),
|
|
'viewer-assets/o3dv/web-ifc-api-iife.js',
|
|
],
|
|
[resolvePackage('web-ifc/web-ifc.wasm'), 'viewer-assets/o3dv/web-ifc.wasm'],
|
|
[
|
|
resolvePackage('draco3d/draco_decoder_nodejs.js'),
|
|
'viewer-assets/o3dv/draco_decoder_nodejs.min.js',
|
|
],
|
|
[
|
|
resolvePackage('occt-import-js/dist/occt-import-js.js'),
|
|
'viewer-assets/o3dv/occt-import-js.js',
|
|
],
|
|
[
|
|
resolvePackage('occt-import-js/dist/occt-import-js-worker.js'),
|
|
'viewer-assets/o3dv/occt-import-js-worker.js',
|
|
],
|
|
[
|
|
resolvePackage('occt-import-js/dist/occt-import-js.wasm'),
|
|
'viewer-assets/o3dv/occt-import-js.wasm',
|
|
],
|
|
[
|
|
resolvePackage('occt-import-js/dist/license.occt-import-js.txt'),
|
|
'viewer-assets/o3dv/licenses/license.occt-import-js.txt',
|
|
],
|
|
[
|
|
resolvePackage('occt-import-js/dist/license.occt.txt'),
|
|
'viewer-assets/o3dv/licenses/license.occt.txt',
|
|
],
|
|
[
|
|
resolvePackage('online-3d-viewer/LICENSE.md'),
|
|
'viewer-assets/o3dv/licenses/online-3d-viewer.LICENSE.md',
|
|
],
|
|
[
|
|
resolvePackage('rhino3dm/README.md'),
|
|
'viewer-assets/o3dv/licenses/rhino3dm.README.md',
|
|
],
|
|
];
|
|
|
|
await Promise.all(
|
|
[...cadAssets, ...o3dvAssets].map(([sources, destination]) =>
|
|
copyFirst(sources, destination),
|
|
),
|
|
);
|
|
|
|
const envmapCandidates = resolvePackage(
|
|
'online-3d-viewer/website/assets/envmaps/fishermans_bastion',
|
|
);
|
|
const envmapDest = path.join(
|
|
publicDir,
|
|
'viewer-assets/o3dv/envmaps/fishermans_bastion',
|
|
);
|
|
await mkdir(path.dirname(envmapDest), { recursive: true });
|
|
{
|
|
let copied = false;
|
|
for (const candidate of envmapCandidates) {
|
|
try {
|
|
await cp(candidate, envmapDest, { recursive: true });
|
|
copied = true;
|
|
break;
|
|
} catch {
|
|
// try next
|
|
}
|
|
}
|
|
if (!copied) {
|
|
throw new Error('Missing Online3DViewer envmap assets');
|
|
}
|
|
}
|
|
|
|
const resources = path.join(publicDir, 'viewer-assets', 'cad-resources');
|
|
await mkdir(path.join(resources, 'fonts'), { recursive: true });
|
|
await mkdir(path.join(resources, 'templates'), { recursive: true });
|
|
const fontManifest = `${JSON.stringify(
|
|
[
|
|
{
|
|
name: [
|
|
'Noto Sans KR',
|
|
'arial',
|
|
'batang',
|
|
'dotum',
|
|
'ghs',
|
|
'gulim',
|
|
'hztxt',
|
|
'isocpeur',
|
|
'malgun',
|
|
'malgun gothic',
|
|
'pmingliu',
|
|
'romans',
|
|
'sanss___',
|
|
'simplex',
|
|
'swisscbo',
|
|
'whgtxt',
|
|
'whs',
|
|
],
|
|
file: 'NotoSansKR-VF.ttf',
|
|
type: 'mesh',
|
|
description: 'Open-source Korean CAD fallback (SIL OFL 1.1)',
|
|
},
|
|
],
|
|
null,
|
|
2,
|
|
)}\n`;
|
|
await Promise.all([
|
|
writeFile(path.join(resources, 'fonts.json'), fontManifest),
|
|
writeFile(path.join(resources, 'fonts', 'fonts.json'), fontManifest),
|
|
]);
|
|
await writeFile(
|
|
path.join(resources, 'README.txt'),
|
|
[
|
|
'Noto Sans KR is bundled as the open-source Korean CAD fallback.',
|
|
'Additional CAD fonts may be placed here when redistribution is permitted.',
|
|
'The read-only viewer does not require a drawing template.',
|
|
'',
|
|
].join('\n'),
|
|
);
|
|
|
|
await writeFile(
|
|
path.join(publicDir, 'viewer-assets/o3dv/README.txt'),
|
|
[
|
|
'Self-hosted Online3DViewer external libraries.',
|
|
'CDN URLs in online-3d-viewer are rewritten to /viewer-assets/o3dv/.',
|
|
'',
|
|
].join('\n'),
|
|
);
|
|
|
|
const O3DV_BASE = '/viewer-assets/o3dv/';
|
|
const replacements = [
|
|
[
|
|
'https://cdn.jsdelivr.net/npm/occt-import-js@0.0.22/dist/',
|
|
O3DV_BASE,
|
|
],
|
|
[
|
|
'https://cdn.jsdelivr.net/npm/rhino3dm@8.17.0/rhino3dm.min.js',
|
|
`${O3DV_BASE}rhino3dm.min.js`,
|
|
],
|
|
[
|
|
'https://cdn.jsdelivr.net/npm/web-ifc@0.0.68/web-ifc-api-iife.js',
|
|
`${O3DV_BASE}web-ifc-api-iife.js`,
|
|
],
|
|
[
|
|
'https://cdn.jsdelivr.net/npm/draco3d@1.5.7/draco_decoder_nodejs.min.js',
|
|
`${O3DV_BASE}draco_decoder_nodejs.min.js`,
|
|
],
|
|
];
|
|
|
|
async function patchO3dvFile(relativePath) {
|
|
for (const candidate of resolvePackage(relativePath)) {
|
|
try {
|
|
let source = await readFile(candidate, 'utf8');
|
|
let changed = false;
|
|
for (const [from, to] of replacements) {
|
|
if (source.includes(from)) {
|
|
source = source.split(from).join(to);
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed) {
|
|
await writeFile(candidate, source);
|
|
console.log(`patched ${candidate}`);
|
|
}
|
|
return;
|
|
} catch {
|
|
// try next path
|
|
}
|
|
}
|
|
throw new Error(`Could not patch ${relativePath}`);
|
|
}
|
|
|
|
await patchO3dvFile('online-3d-viewer/build/engine/o3dv.module.js');
|
|
await patchO3dvFile('online-3d-viewer/build/engine/o3dv.min.js');
|