UNPKG

vite-plugin-wasm-pack

Version:

Vite plugin for rust using wasm-pack 🦀

175 lines (174 loc) • 7.47 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const chalk_1 = __importDefault(require("chalk")); const fs_extra_1 = __importDefault(require("fs-extra")); const narrowing_1 = require("narrowing"); const path_1 = __importDefault(require("path")); /** * return a Vite plugin for handling wasm-pack crate * * only use local crate * * import wasmPack from 'vite-plugin-wasm-pack'; * * plugins: [wasmPack(['./my-local-crate'])] * * only use npm crate, leave the first param to an empty array * * plugins: [wasmPack([],['test-npm-crate'])] * * use both local and npm crate * * plugins: [wasmPack(['./my-local-crate'],['test-npm-crate'])] * * @param crates local crates paths, if you only use crates from npm, leave an empty array here. * @param moduleCrates crates names from npm */ function vitePluginWasmPack(crates, moduleCrates) { const prefix = '@vite-plugin-wasm-pack@'; const pkg = 'pkg'; // default folder of wasm-pack module let config_base; let config_assetsDir; const cratePaths = (0, narrowing_1.isString)(crates) ? [crates] : crates; const modulePaths = !moduleCrates ? [] : (0, narrowing_1.isString)(moduleCrates) ? [moduleCrates] : moduleCrates; // from ../../my-crate -> my_crate_bg.wasm const wasmFilename = (cratePath) => { return path_1.default.basename(cratePath).replace(/\-/g, '_') + '_bg.wasm'; }; // wasmfileName : CrateType const wasmMap = new Map(); // 'my_crate_bg.wasm': {path:'../../my_crate/pkg/my_crate_bg.wasm', isNodeModule: false} cratePaths.forEach((cratePath) => { const wasmFile = wasmFilename(cratePath); wasmMap.set(wasmFile, { path: path_1.default.join(cratePath, pkg, wasmFile), isNodeModule: false }); }); // 'my_crate_bg.wasm': { path: 'node_modules/my_crate/my_crate_bg.wasm', isNodeModule: true } modulePaths.forEach((cratePath) => { const wasmFile = wasmFilename(cratePath); const wasmDirectory = path_1.default.dirname(require.resolve(cratePath)); wasmMap.set(wasmFile, { path: path_1.default.join(wasmDirectory, wasmFile), isNodeModule: true }); }); return { name: 'vite-plugin-wasm-pack', enforce: 'pre', configResolved(resolvedConfig) { config_base = resolvedConfig.base; config_assetsDir = resolvedConfig.build.assetsDir; }, resolveId(id) { for (let i = 0; i < cratePaths.length; i++) { if (path_1.default.basename(cratePaths[i]) === id) return prefix + id; } return null; }, async load(id) { if (id.indexOf(prefix) === 0) { id = id.replace(prefix, ''); const modulejs = path_1.default.join('./node_modules', id, id.replace(/\-/g, '_') + '.js'); const code = await fs_extra_1.default.promises.readFile(modulejs, { encoding: 'utf-8' }); return code; } }, async buildStart(_inputOptions) { const prepareBuild = async (cratePath, isNodeModule) => { const pkgPath = isNodeModule ? path_1.default.dirname(require.resolve(cratePath)) : path_1.default.join(cratePath, pkg); const crateName = path_1.default.basename(cratePath); if (!fs_extra_1.default.existsSync(pkgPath)) { if (isNodeModule) { console.error(chalk_1.default.bold.red('Error: ') + `Can't find ${chalk_1.default.bold(pkgPath)}, run ${chalk_1.default.bold.red(`npm install ${cratePath}`)} first`); } else { console.error(chalk_1.default.bold.red('Error: ') + `Can't find ${chalk_1.default.bold(pkgPath)}, run ${chalk_1.default.bold.red(`wasm-pack build ${cratePath} --target web`)} first`); } } if (!isNodeModule) { // copy pkg generated by wasm-pack to node_modules try { await fs_extra_1.default.copy(pkgPath, path_1.default.join('node_modules', crateName)); } catch (error) { this.error(`copy crates failed`); } } // replace default load path with '/assets/xxx.wasm' const jsName = crateName.replace(/\-/g, '_') + '.js'; /** * if use node module and name is '@group/test' * cratePath === '@group/test' * crateName === 'test' */ let jsPath = path_1.default.join('./node_modules', crateName, jsName); if (isNodeModule) { jsPath = path_1.default.join(pkgPath, jsName); } const regex = /input = new URL\('(.+)'.+;/g; let code = fs_extra_1.default.readFileSync(path_1.default.resolve(jsPath), { encoding: 'utf-8' }); code = code.replace(regex, (_match, group1) => { return `input = "${path_1.default.posix.join(config_base, config_assetsDir, group1)}"`; }); fs_extra_1.default.writeFileSync(jsPath, code); }; for await (const cratePath of cratePaths) { await prepareBuild(cratePath, false); } for await (const cratePath of modulePaths) { await prepareBuild(cratePath, true); } }, configureServer({ middlewares }) { return () => { // send 'root/pkg/xxx.wasm' file to user middlewares.use((req, res, next) => { if ((0, narrowing_1.isString)(req.url)) { const basename = path_1.default.basename(req.url); res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); const entry = wasmMap.get(basename); if (basename.endsWith('.wasm') && entry) { res.writeHead(200, { 'Content-Type': 'application/wasm' }); fs_extra_1.default.createReadStream(entry.path).pipe(res); } else { next(); } } }); }; }, buildEnd() { // copy xxx.wasm files to /assets/xxx.wasm wasmMap.forEach((crate, fileName) => { this.emitFile({ type: 'asset', fileName: `assets/${fileName}`, source: fs_extra_1.default.readFileSync(crate.path) }); }); } }; } exports.default = vitePluginWasmPack; // https://github.com/sveltejs/vite-plugin-svelte/issues/214 if (typeof module !== 'undefined') { module.exports = vitePluginWasmPack; vitePluginWasmPack.default = vitePluginWasmPack; }