From 3cee9683ebb4d3eb0541d0c104f67684b55bb4e3 Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Thu, 24 Jun 2021 01:02:05 +0530 Subject: [PATCH 01/11] feat: support node workers out of the box --- packages/vite/src/node/plugins/worker.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts index 2c2e4501b79ac1..c53f8dd4e4e702 100644 --- a/packages/vite/src/node/plugins/worker.ts +++ b/packages/vite/src/node/plugins/worker.ts @@ -64,8 +64,12 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { format: 'es', sourcemap: config.build.sourcemap }) - - return `const blob = new Blob([atob(\"${Buffer.from(output[0].code).toString('base64')}\")], { type: 'text/javascript;charset=utf-8' }); + + return `const blob = new Blob([atob(\"${Buffer.from( + output[0].code + ).toString( + 'base64' + )}\")], { type: 'text/javascript;charset=utf-8' }); export default function WorkerWrapper() { const objURL = (window.URL || window.webkitURL).createObjectURL(blob); try { @@ -93,6 +97,20 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { query.sharedworker != null ? 'SharedWorker' : 'Worker' const workerOptions = { type: 'module' } + const isNode = (config.build.target as string).includes('node') + + if (isNode) { + return ` + import { Worker } from "worker_threads" \n + import { join } from "path" \n + export default function WorkerWrapper() { + return new ${workerConstructor}(join(__dirname, ${JSON.stringify( + url + )}), ${JSON.stringify(workerOptions, null, 2)}) + } + ` + } + return `export default function WorkerWrapper() { return new ${workerConstructor}(${JSON.stringify( url From cf09753308b0de02d8ebbdfba48b909b651eb9bd Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Sat, 14 Aug 2021 22:13:58 +0530 Subject: [PATCH 02/11] feat: Start tests for worker_thread node --- packages/playground/worker-thread-node/main.ts | 8 ++++++++ .../playground/worker-thread-node/package.json | 10 ++++++++++ .../worker-thread-node/scripts/build.js | 3 +++ .../worker-thread-node/vite.config.js | 17 +++++++++++++++++ .../playground/worker-thread-node/worker.ts | 3 +++ 5 files changed, 41 insertions(+) create mode 100644 packages/playground/worker-thread-node/main.ts create mode 100644 packages/playground/worker-thread-node/package.json create mode 100644 packages/playground/worker-thread-node/scripts/build.js create mode 100644 packages/playground/worker-thread-node/vite.config.js create mode 100644 packages/playground/worker-thread-node/worker.ts diff --git a/packages/playground/worker-thread-node/main.ts b/packages/playground/worker-thread-node/main.ts new file mode 100644 index 00000000000000..ed9288d1c0b0de --- /dev/null +++ b/packages/playground/worker-thread-node/main.ts @@ -0,0 +1,8 @@ +import MyWorker from './worker?worker' + +const run = async () => { + const worker = new MyWorker() + worker.postMessage('ping') +} + +run() diff --git a/packages/playground/worker-thread-node/package.json b/packages/playground/worker-thread-node/package.json new file mode 100644 index 00000000000000..bf8b5c9d4e4aa9 --- /dev/null +++ b/packages/playground/worker-thread-node/package.json @@ -0,0 +1,10 @@ +{ + "name": "worker-thread-node", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "node scripts/build.js", + "start": "node dist/main.cjs.js" + } +} diff --git a/packages/playground/worker-thread-node/scripts/build.js b/packages/playground/worker-thread-node/scripts/build.js new file mode 100644 index 00000000000000..6a8be659344bb3 --- /dev/null +++ b/packages/playground/worker-thread-node/scripts/build.js @@ -0,0 +1,3 @@ +const vite = require('vite') +const { build } = vite +build({ configFile: 'vite.config.js' }) diff --git a/packages/playground/worker-thread-node/vite.config.js b/packages/playground/worker-thread-node/vite.config.js new file mode 100644 index 00000000000000..e4450d055c12a7 --- /dev/null +++ b/packages/playground/worker-thread-node/vite.config.js @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + build: { + target: 'node16', + outDir: 'dist', + lib: { + entry: 'main.ts', + formats: ['cjs'], + fileName: 'main' + }, + rollupOptions: { + external: ['worker_threads', 'path'] + }, + emptyOutDir: true + } +}) diff --git a/packages/playground/worker-thread-node/worker.ts b/packages/playground/worker-thread-node/worker.ts new file mode 100644 index 00000000000000..297f2a85b48260 --- /dev/null +++ b/packages/playground/worker-thread-node/worker.ts @@ -0,0 +1,3 @@ +// import { parentPort } from 'worker_threads' + +// console.log(parentPort) From 13472aa4039d9cef7539b84fb011696fd50789be Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Mon, 16 Aug 2021 03:40:49 +0530 Subject: [PATCH 03/11] feat: Add support for node worker threads inline and file chunk --- packages/vite/client.d.ts | 6 ++-- packages/vite/src/node/plugins/worker.ts | 39 ++++++++++++++++++------ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/packages/vite/client.d.ts b/packages/vite/client.d.ts index 64d1baf86d5d42..14b45f18297e2f 100644 --- a/packages/vite/client.d.ts +++ b/packages/vite/client.d.ts @@ -164,15 +164,17 @@ declare module '*.webmanifest' { // web worker declare module '*?worker' { + import { Worker as NodeWorker } from 'worker_threads' const workerConstructor: { - new (): Worker + new (): Worker | NodeWorker } export default workerConstructor } declare module '*?worker&inline' { + import { Worker as NodeWorker } from 'worker_threads' const workerConstructor: { - new (): Worker + new (): Worker | NodeWorker } export default workerConstructor } diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts index d20c3b53278e0f..92bc3be7b3f140 100644 --- a/packages/vite/src/node/plugins/worker.ts +++ b/packages/vite/src/node/plugins/worker.ts @@ -51,25 +51,46 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { } let url: string + const isNode = (config.build.target as string).includes('node') + if (isBuild) { // bundle the file as entry to support imports const rollup = require('rollup') as typeof Rollup const bundle = await rollup.rollup({ input: cleanUrl(id), + ...config?.build?.rollupOptions, plugins: await resolvePlugins({ ...config }, [], [], []) }) + let code: string try { - const { output } = await bundle.generate({ - format: 'iife', - sourcemap: config.build.sourcemap - }) - code = output[0].code + if (isNode) { + const { output } = await bundle.generate({ + format: 'cjs', + sourcemap: config.build.sourcemap + }) + code = output[0].code + } else { + const { output } = await bundle.generate({ + format: 'iife', + sourcemap: config.build.sourcemap + }) + code = output[0].code + } } finally { await bundle.close() } const content = Buffer.from(code) if (query.inline != null) { + if (isNode) { + return ` + import { Worker } from "worker_threads" \n + import { join } from "path" \n + export default function WorkerWrapper() { + return new Worker(\'${content.toString().trim()}', { eval: true }) + } + ` + } // inline as blob data url return `const blob = new Blob([atob(\"${content.toString( 'base64' @@ -104,16 +125,14 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { query.sharedworker != null ? 'SharedWorker' : 'Worker' const workerOptions = { type: 'module' } - const isNode = (config.build.target as string).includes('node') - if (isNode) { return ` import { Worker } from "worker_threads" \n import { join } from "path" \n export default function WorkerWrapper() { - return new ${workerConstructor}(join(__dirname, ${JSON.stringify( - url - )}), ${JSON.stringify(workerOptions, null, 2)}) + return new Worker(join(__dirname, ${JSON.stringify( + url + )}), ${JSON.stringify(workerOptions, null, 2)}) } ` } From c2782015519acde710d52342c15c70ec9d8d5123 Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Mon, 16 Aug 2021 03:43:17 +0530 Subject: [PATCH 04/11] wip: Support node worker threads tests --- .../__tests__/worker-thread-node.spec.ts | 9 ++++++ .../playground/worker-thread-node/main.ts | 31 ++++++++++++++++--- .../worker-thread-node/scripts/build.js | 2 +- .../{vite.config.js => vite.config.ts} | 3 +- .../worker-thread-node/worker-inline.ts | 5 +++ .../playground/worker-thread-node/worker.ts | 6 ++-- 6 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts rename packages/playground/worker-thread-node/{vite.config.js => vite.config.ts} (77%) create mode 100644 packages/playground/worker-thread-node/worker-inline.ts diff --git a/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts b/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts new file mode 100644 index 00000000000000..cc8603e7d4ed8a --- /dev/null +++ b/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts @@ -0,0 +1,9 @@ +import { run } from '../dist/main.cjs' +import { isBuild } from '../../testUtils' + +if (isBuild) { + test('should return result from worker thread', async () => { + const a = await run('ping') + expect(a).toBe('pong') + }) +} diff --git a/packages/playground/worker-thread-node/main.ts b/packages/playground/worker-thread-node/main.ts index ed9288d1c0b0de..9f5b9f4a84f666 100644 --- a/packages/playground/worker-thread-node/main.ts +++ b/packages/playground/worker-thread-node/main.ts @@ -1,8 +1,31 @@ import MyWorker from './worker?worker' +import InlineWorker from './worker-inline?worker&inline' +import { Worker } from 'worker_threads' -const run = async () => { - const worker = new MyWorker() - worker.postMessage('ping') +export const run = async (message: string): Promise => { + return new Promise((resolve, reject) => { + const worker = new MyWorker() as Worker + worker.postMessage(message) + worker.on('message', (msg) => { + resolve(msg) + }) + }) } -run() +export const inlineWorker = async (message: string): Promise => { + return new Promise((resolve, reject) => { + const worker = new InlineWorker() as Worker + worker.postMessage(message) + worker.on('message', (msg) => { + resolve(msg) + }) + }) +} + +run('ping').then((a) => { + console.log(a) +}) + +inlineWorker('ping').then((a) => { + console.log(a) +}) diff --git a/packages/playground/worker-thread-node/scripts/build.js b/packages/playground/worker-thread-node/scripts/build.js index 6a8be659344bb3..8f2af5599d0fa4 100644 --- a/packages/playground/worker-thread-node/scripts/build.js +++ b/packages/playground/worker-thread-node/scripts/build.js @@ -1,3 +1,3 @@ const vite = require('vite') const { build } = vite -build({ configFile: 'vite.config.js' }) +build({ configFile: 'vite.config.ts' }) diff --git a/packages/playground/worker-thread-node/vite.config.js b/packages/playground/worker-thread-node/vite.config.ts similarity index 77% rename from packages/playground/worker-thread-node/vite.config.js rename to packages/playground/worker-thread-node/vite.config.ts index e4450d055c12a7..b303b0cde76ef3 100644 --- a/packages/playground/worker-thread-node/vite.config.js +++ b/packages/playground/worker-thread-node/vite.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from 'vite' +import { builtinModules } from 'module' export default defineConfig({ build: { @@ -10,7 +11,7 @@ export default defineConfig({ fileName: 'main' }, rollupOptions: { - external: ['worker_threads', 'path'] + external: [...builtinModules] }, emptyOutDir: true } diff --git a/packages/playground/worker-thread-node/worker-inline.ts b/packages/playground/worker-thread-node/worker-inline.ts new file mode 100644 index 00000000000000..c4b77ced37cfb6 --- /dev/null +++ b/packages/playground/worker-thread-node/worker-inline.ts @@ -0,0 +1,5 @@ +import { parentPort } from 'worker_threads' + +parentPort.on('message', () => { + parentPort.postMessage('this is inline node worker') +}) diff --git a/packages/playground/worker-thread-node/worker.ts b/packages/playground/worker-thread-node/worker.ts index 297f2a85b48260..64095313371ec3 100644 --- a/packages/playground/worker-thread-node/worker.ts +++ b/packages/playground/worker-thread-node/worker.ts @@ -1,3 +1,5 @@ -// import { parentPort } from 'worker_threads' +import { parentPort } from 'worker_threads' -// console.log(parentPort) +parentPort.on('message', (message) => { + parentPort.postMessage('pong') +}) From 0f39f11a76ad12e5a52ab206705fc7897c5f5dd3 Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Mon, 16 Aug 2021 14:50:05 +0530 Subject: [PATCH 05/11] feat: worker_threads node tests complete --- .../worker-thread-node/__tests__/serve.js | 23 +++++++++ .../__tests__/worker-thread-node.spec.ts | 49 +++++++++++++++++-- .../playground/worker-thread-node/main.ts | 18 ++++--- .../worker-thread-node/package.json | 2 +- 4 files changed, 79 insertions(+), 13 deletions(-) create mode 100644 packages/playground/worker-thread-node/__tests__/serve.js diff --git a/packages/playground/worker-thread-node/__tests__/serve.js b/packages/playground/worker-thread-node/__tests__/serve.js new file mode 100644 index 00000000000000..e6033954ed411b --- /dev/null +++ b/packages/playground/worker-thread-node/__tests__/serve.js @@ -0,0 +1,23 @@ +const { join } = require('path') +/** + * @param {string} root + * @param {boolean} isProd + */ +exports.serve = async function serve(root, isProd) { + if (isProd) { + const { build } = require('vite') + await build({ + configFile: join(root, 'vite.config.ts'), + root, + logLevel: 'silent' + }) + } + + return new Promise((resolve, _) => { + resolve({ + close: async () => { + // no need to close anything + } + }) + }) +} diff --git a/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts b/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts index cc8603e7d4ed8a..cddb9e538232f3 100644 --- a/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts +++ b/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts @@ -1,9 +1,48 @@ -import { run } from '../dist/main.cjs' -import { isBuild } from '../../testUtils' +import { isBuild, testDir } from '../../testUtils' +import fs from 'fs-extra' +import path from 'path' if (isBuild) { - test('should return result from worker thread', async () => { - const a = await run('ping') - expect(a).toBe('pong') + test('response from worker', async () => { + const distDir = path.resolve(testDir, 'dist') + const { run } = require(path.join(distDir, 'main.cjs')) + expect(await run('ping')).toBe('pong') + }) + + test('response from inline worker', async () => { + const distDir = path.resolve(testDir, 'dist') + const { inlineWorker } = require(path.join(distDir, 'main.cjs')) + expect(await inlineWorker('ping')).toBe('this is inline node worker') + }) + + test('worker code generation', async () => { + const assetsDir = path.resolve(testDir, 'dist/assets') + const distDir = path.resolve(testDir, 'dist') + const files = fs.readdirSync(assetsDir) + const mainContent = fs.readFileSync( + path.resolve(distDir, 'main.cjs.js'), + 'utf-8' + ) + + const workerFile = files.find((f) => f.includes('worker')) + const workerContent = fs.readFileSync( + path.resolve(assetsDir, workerFile), + 'utf-8' + ) + + expect(files.length).toBe(1) + + // main file worker chunk content + expect(mainContent).toMatch(`require("worker_threads")`) + expect(mainContent).toMatch(`Worker`) + + // main content should contain __dirname to resolve module as relation path from main module + expect(mainContent).toMatch(`__dirname`) + + // should resolve worker_treads from external dependency + expect(workerContent).toMatch(`require("worker_threads")`) + + // inline nodejs worker + expect(mainContent).toMatch(`{eval:!0}`) }) } diff --git a/packages/playground/worker-thread-node/main.ts b/packages/playground/worker-thread-node/main.ts index 9f5b9f4a84f666..694dcee60e2b8a 100644 --- a/packages/playground/worker-thread-node/main.ts +++ b/packages/playground/worker-thread-node/main.ts @@ -7,6 +7,7 @@ export const run = async (message: string): Promise => { const worker = new MyWorker() as Worker worker.postMessage(message) worker.on('message', (msg) => { + worker.terminate() resolve(msg) }) }) @@ -17,15 +18,18 @@ export const inlineWorker = async (message: string): Promise => { const worker = new InlineWorker() as Worker worker.postMessage(message) worker.on('message', (msg) => { + worker.terminate() resolve(msg) }) }) } -run('ping').then((a) => { - console.log(a) -}) - -inlineWorker('ping').then((a) => { - console.log(a) -}) +if (require.main === module) { + Promise.all([run('ping'), inlineWorker('ping')]).then( + ([chunkResponse, inlineResponse]) => { + console.log('Response from chunk worker - ', chunkResponse) + console.log('Response from inline worker - ', inlineResponse) + process.exit() + } + ) +} diff --git a/packages/playground/worker-thread-node/package.json b/packages/playground/worker-thread-node/package.json index bf8b5c9d4e4aa9..5371fcbc5e3f71 100644 --- a/packages/playground/worker-thread-node/package.json +++ b/packages/playground/worker-thread-node/package.json @@ -3,7 +3,7 @@ "private": true, "version": "0.0.0", "scripts": { - "dev": "vite", + "dev": "node scripts/build.js", "build": "node scripts/build.js", "start": "node dist/main.cjs.js" } From e10dffb274ca1e4c4b5dddf979f5aea2c5a66af8 Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Mon, 16 Aug 2021 15:26:59 +0530 Subject: [PATCH 06/11] refactor: add isTargetNode utility function --- packages/vite/src/node/plugins/worker.ts | 4 ++-- packages/vite/src/node/utils.ts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts index 92bc3be7b3f140..51e0d939e842a9 100644 --- a/packages/vite/src/node/plugins/worker.ts +++ b/packages/vite/src/node/plugins/worker.ts @@ -3,7 +3,7 @@ import { Plugin } from '../plugin' import { resolvePlugins } from '../plugins' import { parse as parseUrl, URLSearchParams } from 'url' import { fileToUrl, getAssetHash } from './asset' -import { cleanUrl, injectQuery } from '../utils' +import { cleanUrl, injectQuery, isTargetNode } from '../utils' import Rollup from 'rollup' import { ENV_PUBLIC_PATH } from '../constants' import path from 'path' @@ -51,7 +51,7 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { } let url: string - const isNode = (config.build.target as string).includes('node') + const isNode = isTargetNode(config?.build?.target) if (isBuild) { // bundle the file as entry to support imports diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 305e08ce37796a..8342651e817c73 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -512,3 +512,19 @@ export function resolveHostname( return { host, name } } + +export function isTargetNode(target: string | false | string[]): boolean { + if (!target) { + return false + } + + if (typeof target === 'string') { + return target.includes('node') + } + + if (Array.isArray(target)) { + return Boolean(target.filter((f) => f.includes('node')).length) + } + + return false +} From a4a72b78ac05a7c2330e7f2612465d1b83ba5023 Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Mon, 16 Aug 2021 17:28:09 +0530 Subject: [PATCH 07/11] refactor: suggested code changes --- packages/vite/src/node/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 8342651e817c73..12a352876792b0 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -523,7 +523,7 @@ export function isTargetNode(target: string | false | string[]): boolean { } if (Array.isArray(target)) { - return Boolean(target.filter((f) => f.includes('node')).length) + return target.some((f) => f.includes('node')) } return false From 4820e7bea458bd8ee352761109e368d5c967066d Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Mon, 16 Aug 2021 20:09:11 +0530 Subject: [PATCH 08/11] fix: token error with inline worker if minify is false --- .../worker-thread-node/__tests__/serve.js | 11 +++++++++ .../__tests__/worker-thread-node.spec.ts | 24 +++++++++---------- .../worker-thread-node/vite.config.ts | 17 +++++++++++++ packages/vite/src/node/plugins/worker.ts | 5 +++- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/packages/playground/worker-thread-node/__tests__/serve.js b/packages/playground/worker-thread-node/__tests__/serve.js index e6033954ed411b..bc8502d623c879 100644 --- a/packages/playground/worker-thread-node/__tests__/serve.js +++ b/packages/playground/worker-thread-node/__tests__/serve.js @@ -4,6 +4,8 @@ const { join } = require('path') * @param {boolean} isProd */ exports.serve = async function serve(root, isProd) { + // make a build in either cases + // make minified build if prod if (isProd) { const { build } = require('vite') await build({ @@ -11,6 +13,15 @@ exports.serve = async function serve(root, isProd) { root, logLevel: 'silent' }) + } else { + const { build } = require('vite') + + const config = require(join(root, 'vite.config.ts')).serveConfig + await build({ + ...config, + root, + logLevel: 'silent' + }) } return new Promise((resolve, _) => { diff --git a/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts b/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts index cddb9e538232f3..a8d64dbc2d6c79 100644 --- a/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts +++ b/packages/playground/worker-thread-node/__tests__/worker-thread-node.spec.ts @@ -2,19 +2,19 @@ import { isBuild, testDir } from '../../testUtils' import fs from 'fs-extra' import path from 'path' -if (isBuild) { - test('response from worker', async () => { - const distDir = path.resolve(testDir, 'dist') - const { run } = require(path.join(distDir, 'main.cjs')) - expect(await run('ping')).toBe('pong') - }) - - test('response from inline worker', async () => { - const distDir = path.resolve(testDir, 'dist') - const { inlineWorker } = require(path.join(distDir, 'main.cjs')) - expect(await inlineWorker('ping')).toBe('this is inline node worker') - }) +test('response from worker', async () => { + const distDir = path.resolve(testDir, 'dist') + const { run } = require(path.join(distDir, 'main.cjs')) + expect(await run('ping')).toBe('pong') +}) + +test('response from inline worker', async () => { + const distDir = path.resolve(testDir, 'dist') + const { inlineWorker } = require(path.join(distDir, 'main.cjs')) + expect(await inlineWorker('ping')).toBe('this is inline node worker') +}) +if (isBuild) { test('worker code generation', async () => { const assetsDir = path.resolve(testDir, 'dist/assets') const distDir = path.resolve(testDir, 'dist') diff --git a/packages/playground/worker-thread-node/vite.config.ts b/packages/playground/worker-thread-node/vite.config.ts index b303b0cde76ef3..ab709ff9df6000 100644 --- a/packages/playground/worker-thread-node/vite.config.ts +++ b/packages/playground/worker-thread-node/vite.config.ts @@ -16,3 +16,20 @@ export default defineConfig({ emptyOutDir: true } }) + +export const serveConfig = defineConfig({ + build: { + target: 'node16', + outDir: 'dist', + lib: { + entry: 'main.ts', + formats: ['cjs'], + fileName: 'main' + }, + rollupOptions: { + external: [...builtinModules] + }, + minify: false, + emptyOutDir: true + } +}) diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts index 51e0d939e842a9..773354f371d0ba 100644 --- a/packages/vite/src/node/plugins/worker.ts +++ b/packages/vite/src/node/plugins/worker.ts @@ -83,11 +83,14 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { const content = Buffer.from(code) if (query.inline != null) { if (isNode) { + let code = content.toString().trim() + code = code.replace(/\r?\n|\r/g, '') + return ` import { Worker } from "worker_threads" \n import { join } from "path" \n export default function WorkerWrapper() { - return new Worker(\'${content.toString().trim()}', { eval: true }) + return new Worker(\'${code}', { eval: true }) } ` } From 0fc80324f935203581248632cf9dce1eb8cca064 Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Thu, 19 Aug 2021 01:02:22 +0530 Subject: [PATCH 09/11] refactor: revert worker type from union to web worker --- packages/playground/worker-thread-node/main.ts | 8 ++++---- packages/vite/client.d.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/playground/worker-thread-node/main.ts b/packages/playground/worker-thread-node/main.ts index 694dcee60e2b8a..3683a1f8dd7819 100644 --- a/packages/playground/worker-thread-node/main.ts +++ b/packages/playground/worker-thread-node/main.ts @@ -3,8 +3,8 @@ import InlineWorker from './worker-inline?worker&inline' import { Worker } from 'worker_threads' export const run = async (message: string): Promise => { - return new Promise((resolve, reject) => { - const worker = new MyWorker() as Worker + return new Promise((resolve, _) => { + const worker = new MyWorker() as unknown as Worker worker.postMessage(message) worker.on('message', (msg) => { worker.terminate() @@ -14,8 +14,8 @@ export const run = async (message: string): Promise => { } export const inlineWorker = async (message: string): Promise => { - return new Promise((resolve, reject) => { - const worker = new InlineWorker() as Worker + return new Promise((resolve, _) => { + const worker = new InlineWorker() as unknown as Worker worker.postMessage(message) worker.on('message', (msg) => { worker.terminate() diff --git a/packages/vite/client.d.ts b/packages/vite/client.d.ts index 14b45f18297e2f..0c014a2c652174 100644 --- a/packages/vite/client.d.ts +++ b/packages/vite/client.d.ts @@ -166,7 +166,7 @@ declare module '*.webmanifest' { declare module '*?worker' { import { Worker as NodeWorker } from 'worker_threads' const workerConstructor: { - new (): Worker | NodeWorker + new (): Worker } export default workerConstructor } @@ -174,7 +174,7 @@ declare module '*?worker' { declare module '*?worker&inline' { import { Worker as NodeWorker } from 'worker_threads' const workerConstructor: { - new (): Worker | NodeWorker + new (): Worker } export default workerConstructor } From b434633460d03e80c16aaf9de6d6521ebe224f7e Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Thu, 19 Aug 2021 15:46:36 +0530 Subject: [PATCH 10/11] refactor: remove unwanted imports --- packages/vite/client.d.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/vite/client.d.ts b/packages/vite/client.d.ts index 0c014a2c652174..64d1baf86d5d42 100644 --- a/packages/vite/client.d.ts +++ b/packages/vite/client.d.ts @@ -164,7 +164,6 @@ declare module '*.webmanifest' { // web worker declare module '*?worker' { - import { Worker as NodeWorker } from 'worker_threads' const workerConstructor: { new (): Worker } @@ -172,7 +171,6 @@ declare module '*?worker' { } declare module '*?worker&inline' { - import { Worker as NodeWorker } from 'worker_threads' const workerConstructor: { new (): Worker } From aafe437e4f06a4795efcbf58ac86407d251191d2 Mon Sep 17 00:00:00 2001 From: Prathamesh Date: Thu, 2 Sep 2021 00:32:21 +0530 Subject: [PATCH 11/11] feat: node worker docs --- docs/guide/features.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/guide/features.md b/docs/guide/features.md index dd7d649f8eb014..2d21e7e4f42cd1 100644 --- a/docs/guide/features.md +++ b/docs/guide/features.md @@ -306,6 +306,22 @@ By default, the worker script will be emitted as a separate chunk in the product import MyWorker from './worker?worker&inline' ``` +## Node Worker Threads + +Just like Web Workers Node.js worker threads are supported out of the box. You will need to set build target to nodeN and add native modules as external dependencies in rollup options in config. A Node.js worker script can imported by appending `?worker` to the import request. The default export will be the Worker class from the native 'worker_threads' module. Typescript worker file is also supported. + +```js +import MyWorker from './worker?worker' + +const worker = new MyWorker() +``` + +By default, the worker script will be emitted as a separate chunk in the production build. If you wish to inline the worker, add the `inline` query. Inline code will be added with `{eval: true}` + +```js +import MyWorker from './worker?worker&inline' +``` + ## Build Optimizations > Features listed below are automatically applied as part of the build process and there is no need for explicit configuration unless you want to disable them.