This guide shows how to use web-csv-toolbox with popular JavaScript bundlers when using Worker-based or WebAssembly execution.
import { parseString, EnginePresets } from 'web-csv-toolbox';
import workerUrl from 'web-csv-toolbox/worker?url';
const csv = `name,age,city
Alice,30,New York
Bob,25,London`;
for await (const record of parseString(csv, {
engine: EnginePresets.responsive({ workerURL: workerUrl })
})) {
console.log(record);
}
No configuration needed. Vite automatically handles the ?url suffix.
import { parseString, EnginePresets } from 'web-csv-toolbox';
const workerUrl = new URL('web-csv-toolbox/worker', import.meta.url);
for await (const record of parseString(csv, {
engine: EnginePresets.responsive({ workerURL: workerUrl })
})) {
console.log(record);
}
No configuration needed. Webpack 5 automatically handles new URL() with import.meta.url.
If you prefer not to use Workers, use the main thread engine:
import { parseString, EnginePresets } from 'web-csv-toolbox';
for await (const record of parseString(csv, {
engine: EnginePresets.stable()
})) {
console.log(record);
}
No bundler configuration needed.
When using WebAssembly for improved performance, bundlers require explicit WASM URL configuration.
Unlike Workers which can be bundled as data URLs, WASM modules are loaded at runtime via import.meta.url. Bundlers need to know where to find the WASM file.
import { loadWASM, parseString, EnginePresets } from 'web-csv-toolbox';
// Copy node_modules/web-csv-toolbox/dist/csv.wasm
// to public/csv.wasm
await loadWASM('/csv.wasm');
for await (const record of parseString(csv, {
engine: EnginePresets.responsiveFast() // Uses WASM + Worker
})) {
console.log(record);
}
Add a build step to copy the WASM file:
{
"scripts": {
"prebuild": "cp node_modules/web-csv-toolbox/dist/csv.wasm public/"
}
}
?url import with explicit URL (Recommended)import { loadWASM, parseString, EnginePresets } from 'web-csv-toolbox';
import wasmUrl from 'web-csv-toolbox/csv.wasm?url';
await loadWASM(wasmUrl);
for await (const record of parseString(csv, {
engine: EnginePresets.responsiveFast()
})) {
console.log(record);
}
Vite will copy the WASM file to your dist folder automatically.
If you want to minimize bundle size, use the slim variant which doesn't include inlined WASM:
import { loadWASM, parseString, EnginePresets, ReusableWorkerPool } from 'web-csv-toolbox/slim';
import workerUrl from 'web-csv-toolbox/worker/slim?url';
import wasmUrl from 'web-csv-toolbox/csv.wasm?url';
// Initialize WASM before using it
await loadWASM(wasmUrl);
using pool = new ReusableWorkerPool({
maxWorkers: 2,
workerURL: workerUrl,
});
for await (const record of parseString(csv, {
engine: {
worker: true,
wasm: true,
workerPool: pool,
}
})) {
console.log(record);
}
web-csv-toolbox): WASM embedded as base64 - larger initial bundle, auto-initializationweb-csv-toolbox/slim): WASM loaded separately - smaller initial bundle, manual initialization requiredWhen using ?url imports, you need to configure TypeScript to recognize these imports:
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"moduleResolution": "bundler",
"types": ["vite/client"] // Required for ?url suffix types
}
}
To ensure WASM files are included in the build output:
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
resolve: {
// Ensure browser build is selected
conditions: ['browser', 'import', 'module', 'default'],
mainFields: ['browser', 'module', 'main'],
},
// Include WASM files in build output
assetsInclude: ['**/*.wasm'],
});
Why assetsInclude is needed:
?url importsassetsInclude ensures WASM files are always copied to the build outputimport { loadWASM, parseString } from 'web-csv-toolbox';
const wasmUrl = new URL('web-csv-toolbox/csv.wasm', import.meta.url);
await loadWASM(wasmUrl);
Configure Webpack to handle WASM files:
// webpack.config.js
module.exports = {
experiments: {
asyncWebAssembly: true
},
module: {
rules: [
{
test: /\.wasm$/,
type: 'asset/resource'
}
]
}
};
When using both Workers and WASM (via EnginePresets.responsiveFast()), you need to configure both.
import { loadWASM, parseString, EnginePresets } from 'web-csv-toolbox';
import workerUrl from 'web-csv-toolbox/worker?url';
import wasmUrl from 'web-csv-toolbox/csv.wasm?url';
// Optional: Pre-load WASM to reduce first-parse latency
await loadWASM(wasmUrl);
for await (const record of parseString(csv, {
engine: EnginePresets.responsiveFast({ workerURL: workerUrl })
})) {
console.log(record);
}
import { loadWASM, parseString, ReusableWorkerPool } from 'web-csv-toolbox/slim';
import workerUrl from 'web-csv-toolbox/worker/slim?url';
import wasmUrl from 'web-csv-toolbox/csv.wasm?url';
// Required: Initialize WASM before parsing
await loadWASM(wasmUrl);
using pool = new ReusableWorkerPool({
maxWorkers: 2,
workerURL: workerUrl,
});
for await (const record of parseString(csv, {
engine: {
worker: true,
wasm: true,
workerPool: pool,
}
})) {
console.log(record);
}
Important Notes:
loadWASM() ahead of time is optional but reduces first-parse latency.loadWASM(wasmUrl) before parsing. Without it, WASM-based parsing will fail.The package automatically selects the correct Worker implementation:
worker.node.js)worker.web.js)This is configured via package.json exports:
{
"exports": {
"./worker": {
"node": "./dist/worker.node.js",
"browser": "./dist/worker.web.js",
"default": "./dist/worker.web.js"
}
}
}
For better performance when parsing multiple files, use a WorkerPool:
import { parseString, EnginePresets, ReusableWorkerPool } from 'web-csv-toolbox';
import workerUrl from 'web-csv-toolbox/worker?url';
using pool = new ReusableWorkerPool({
maxWorkers: 4,
workerURL: workerUrl
});
const files = [csv1, csv2, csv3];
await Promise.all(
files.map(async (csv) => {
let count = 0;
for await (const record of parseString(csv, {
engine: EnginePresets.responsive({ workerPool: pool })
})) {
// Process record
count++;
}
return count;
})
);
?url suffixSymptom: Cannot find module 'web-csv-toolbox/worker?url' or its corresponding type declarations
Cause: Missing TypeScript configuration for Vite's ?url imports.
Solution: Add vite/client to your tsconfig.json:
{
"compilerOptions": {
"types": ["vite/client"]
}
}
This enables TypeScript to recognize Vite's special import suffixes like ?url, ?worker, etc.
Make sure you're importing with the correct syntax for your bundler:
import workerUrl from 'web-csv-toolbox/worker?url'new URL('web-csv-toolbox/worker', import.meta.url)Symptom: Error like RuntimeError: Aborted(CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d)
Causes:
Solutions:
// ✅ Good: Explicit URL
import wasmUrl from 'web-csv-toolbox/csv.wasm?url';
await loadWASM(wasmUrl);
// ❌ Bad: Missing loadWASM call
await loadWASM(); // May fail if bundler doesn't copy WASM file
Check your bundler configuration ensures WASM files are copied to the output directory.
If using data URLs (Vite's default), ensure your CSP allows them:
Content-Security-Policy: worker-src 'self' blob: data:; script-src 'self' 'wasm-unsafe-eval';
For WASM: Add 'wasm-unsafe-eval' to script-src directive.
To avoid data URLs, configure your bundler to emit Workers as separate files.
For complete, working examples with different bundlers and configurations: