vite-node 0.1.11 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,7 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Anthony Fu <https://github.com/antfu>
3
+ Copyright (c) 2021-Present Anthony Fu <https://github.com/antfu>
4
+ Copyright (c) 2021-Present Matias Capeletto <https://github.com/patak-dev>
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
7
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,12 +2,20 @@
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/vite-node?color=a1b858&label=)](https://www.npmjs.com/package/vite-node)
4
4
 
5
- Vite as Node runtime.
5
+ Vite as Node runtime. The engine powers [Vitest](https://github.com/vitest-dev/vitest).
6
6
 
7
- > **EXPERIMENTAL**
7
+ ## Features
8
+
9
+ - Out-of-box ESM & TypeScript support (possible for more with plugins)
10
+ - Top-level await
11
+ - Vite plugins, resolve, aliasing
12
+ - Respect `vite.config.ts`
13
+ - Shims for `__dirname` and `__filename` in ESM
14
+ - Access to native node modules like `fs`, `path`, etc.
8
15
 
16
+ ## CLI Usage
9
17
 
10
- ## Usage
18
+ Run JS/TS file on Node.js using Vite's resolvers and transformers.
11
19
 
12
20
  ```bash
13
21
  npx vite-node index.ts
@@ -19,29 +27,41 @@ Options:
19
27
  npx vite-node -h
20
28
  ```
21
29
 
22
- ## Features
30
+ ## Programmatic Usage
23
31
 
24
- - Out-of-box ESM & TypeScript support (possible for more with plugins)
25
- - Top-level await
26
- - Vite plugins, resolve, aliasing
27
- - Respect `vite.config.ts`
28
- - Shims for `__dirname` and `__filename` in ESM
29
- - Access to native node modules like `fs`, `path`, etc.
30
- - Watch mode (like `nodemon`)
32
+ In Vite Node, the server and runner (client) are separated, so you can integrate them in different contexts (workers, cross-process, or remote) if needed. The demo below shows a simple example of having the server and running in the same context
31
33
 
32
- ## When NOT to Use
34
+ ```ts
35
+ import { createServer } from 'vite'
36
+ import { ViteNodeServer } from 'vite-node/server'
37
+ import { ViteNodeRunner } from 'vite-node/client'
33
38
 
34
- - Production, yet - in very early stage, check it later
35
- - Most of the time, when other tools can do that job
36
- - We need to start a Vite server upon each execution, which inevitably introduces some overhead. Only use it when you want the same behavior as Vite or the powerful plugins system (for example, testing components with a Vite-specific setup).
39
+ // create vite server
40
+ const server = await createServer()
41
+ // this is need to initialize the plugins
42
+ await server.pluginContainer.buildStart({})
37
43
 
38
- ## Why?
44
+ // create vite-node server
45
+ const node = new ViteNodeServer(server)
39
46
 
40
- It runs Vite's id resolving, module transforming, and most importantly, the powerful plugins system!
47
+ // create vite-node runner
48
+ const runner = new ViteNodeRunner({
49
+ root: server.config.root,
50
+ base: server.config.base,
51
+ // when having the server and runner in a different context,
52
+ // you will need to handle the communication between them
53
+ // and pass to this function
54
+ fetchModule(id) {
55
+ return node.fetchModule(id)
56
+ },
57
+ })
41
58
 
42
- ## How?
59
+ // execute the file
60
+ await runner.executeFile('./example.ts')
43
61
 
44
- It fires up a Vite dev server, transforms the requests, and runs them in Node.
62
+ // close the vite server
63
+ await server.close()
64
+ ```
45
65
 
46
66
  ## Credits
47
67
 
package/cli.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ interface CliOptions {
2
+ files?: string[];
3
+ _?: string[];
4
+ root?: string;
5
+ config?: string;
6
+ }
7
+
8
+ export { CliOptions };
package/client.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ declare type FetchFunction = (id: string) => Promise<{
2
+ code?: string;
3
+ externalize?: string;
4
+ }>;
5
+ interface ModuleCache {
6
+ promise?: Promise<any>;
7
+ exports?: any;
8
+ code?: string;
9
+ }
10
+ interface ViteNodeRunnerOptions {
11
+ fetchModule: FetchFunction;
12
+ root: string;
13
+ base?: string;
14
+ moduleCache?: Map<string, ModuleCache>;
15
+ interpretDefault?: boolean;
16
+ requestStubs?: Record<string, any>;
17
+ }
18
+
19
+ declare class ViteNodeRunner {
20
+ options: ViteNodeRunnerOptions;
21
+ root: string;
22
+ externalCache: Map<string, string | Promise<false | string>>;
23
+ moduleCache: Map<string, ModuleCache>;
24
+ constructor(options: ViteNodeRunnerOptions);
25
+ executeFile(file: string): Promise<any>;
26
+ executeId(id: string): Promise<any>;
27
+ cachedRequest(rawId: string, callstack: string[]): Promise<any>;
28
+ directRequest(id: string, fsPath: string, callstack: string[]): Promise<any>;
29
+ prepareContext(context: Record<string, any>): Record<string, any>;
30
+ setCache(id: string, mod: Partial<ModuleCache>): void;
31
+ }
32
+
33
+ export { ViteNodeRunner };
package/dist/cli.js ADDED
@@ -0,0 +1,78 @@
1
+ import minimist from 'minimist';
2
+ import { red, dim } from 'kolorist';
3
+ import { createServer } from 'vite';
4
+ import { ViteNodeServer } from './server.js';
5
+ import { ViteNodeRunner } from './client.js';
6
+ import 'fs';
7
+ import 'mlly';
8
+ import './utils.js';
9
+ import 'url';
10
+ import 'pathe';
11
+ import 'module';
12
+ import 'vm';
13
+
14
+ const argv = minimist(process.argv.slice(2), {
15
+ "alias": {
16
+ r: "root",
17
+ c: "config",
18
+ h: "help",
19
+ w: "watch",
20
+ s: "silent"
21
+ },
22
+ "--": true,
23
+ "string": ["root", "config"],
24
+ "boolean": ["help", "watch", "silent"],
25
+ unknown(name) {
26
+ if (name[0] === "-") {
27
+ console.error(red(`Unknown argument: ${name}`));
28
+ help();
29
+ process.exit(1);
30
+ }
31
+ return true;
32
+ }
33
+ });
34
+ if (argv.help) {
35
+ help();
36
+ process.exit(0);
37
+ }
38
+ if (!argv._.length) {
39
+ console.error(red("No files specified."));
40
+ help();
41
+ process.exit(1);
42
+ }
43
+ process.argv = [...process.argv.slice(0, 2), ...argv["--"] || []];
44
+ run(argv);
45
+ function help() {
46
+ console.log(`
47
+ Usage:
48
+ $ vite-node [options] [files]
49
+
50
+ Options:
51
+ -r, --root <path> ${dim("[string]")} use specified root directory
52
+ -c, --config <file> ${dim("[string]")} use specified config file
53
+ -w, --watch ${dim("[boolean]")} restart on file changes, similar to "nodemon"
54
+ -s, --silent ${dim("[boolean]")} do not emit errors and logs
55
+ --vue ${dim("[boolean]")} support for importing Vue component
56
+ `);
57
+ }
58
+ async function run(options = {}) {
59
+ const files = options.files || options._ || [];
60
+ const server = await createServer({
61
+ logLevel: "error",
62
+ clearScreen: false,
63
+ configFile: options.config,
64
+ root: options.root
65
+ });
66
+ await server.pluginContainer.buildStart({});
67
+ const node = new ViteNodeServer(server);
68
+ const runner = new ViteNodeRunner({
69
+ root: server.config.root,
70
+ base: server.config.base,
71
+ fetchModule(id) {
72
+ return node.fetchModule(id);
73
+ }
74
+ });
75
+ for (const file of files)
76
+ await runner.executeFile(file);
77
+ await server.close();
78
+ }
package/dist/client.js ADDED
@@ -0,0 +1,141 @@
1
+ import { builtinModules, createRequire } from 'module';
2
+ import { pathToFileURL, fileURLToPath } from 'url';
3
+ import vm from 'vm';
4
+ import { resolve, dirname } from 'pathe';
5
+ import { slash, normalizeId, toFilePath, isPrimitive } from './utils.js';
6
+
7
+ class ViteNodeRunner {
8
+ constructor(options) {
9
+ this.options = options;
10
+ this.root = options.root || process.cwd();
11
+ this.moduleCache = options.moduleCache || new Map();
12
+ this.externalCache = new Map();
13
+ builtinModules.forEach((m) => this.externalCache.set(m, m));
14
+ }
15
+ async executeFile(file) {
16
+ return await this.cachedRequest(`/@fs/${slash(resolve(file))}`, []);
17
+ }
18
+ async executeId(id) {
19
+ return await this.cachedRequest(id, []);
20
+ }
21
+ async cachedRequest(rawId, callstack) {
22
+ var _a, _b;
23
+ const id = normalizeId(rawId, this.options.base);
24
+ const fsPath = toFilePath(id, this.root);
25
+ if ((_a = this.moduleCache.get(fsPath)) == null ? void 0 : _a.promise)
26
+ return (_b = this.moduleCache.get(fsPath)) == null ? void 0 : _b.promise;
27
+ const promise = this.directRequest(id, fsPath, callstack);
28
+ this.setCache(fsPath, { promise });
29
+ return await promise;
30
+ }
31
+ async directRequest(id, fsPath, callstack) {
32
+ callstack = [...callstack, id];
33
+ const request = async (dep) => {
34
+ var _a;
35
+ if (callstack.includes(dep)) {
36
+ const cacheKey = toFilePath(dep, this.root);
37
+ if (!((_a = this.moduleCache.get(cacheKey)) == null ? void 0 : _a.exports))
38
+ throw new Error(`Circular dependency detected
39
+ Stack:
40
+ ${[...callstack, dep].reverse().map((p) => `- ${p}`).join("\n")}`);
41
+ return this.moduleCache.get(cacheKey).exports;
42
+ }
43
+ return this.cachedRequest(dep, callstack);
44
+ };
45
+ if (this.options.requestStubs && id in this.options.requestStubs)
46
+ return this.options.requestStubs[id];
47
+ const { code: transformed, externalize } = await this.options.fetchModule(id);
48
+ if (externalize) {
49
+ const mod = await interpretedImport(externalize, this.options.interpretDefault ?? true);
50
+ this.setCache(fsPath, { exports: mod });
51
+ return mod;
52
+ }
53
+ if (transformed == null)
54
+ throw new Error(`failed to load ${id}`);
55
+ const url = pathToFileURL(fsPath).href;
56
+ const exports = {};
57
+ this.setCache(fsPath, { code: transformed, exports });
58
+ const __filename = fileURLToPath(url);
59
+ const moduleProxy = {
60
+ set exports(value) {
61
+ exportAll(exports, value);
62
+ exports.default = value;
63
+ },
64
+ get exports() {
65
+ return exports.default;
66
+ }
67
+ };
68
+ const context = this.prepareContext({
69
+ __vite_ssr_import__: request,
70
+ __vite_ssr_dynamic_import__: request,
71
+ __vite_ssr_exports__: exports,
72
+ __vite_ssr_exportAll__: (obj) => exportAll(exports, obj),
73
+ __vite_ssr_import_meta__: { url },
74
+ require: createRequire(url),
75
+ exports,
76
+ module: moduleProxy,
77
+ __filename,
78
+ __dirname: dirname(__filename)
79
+ });
80
+ const fn = vm.runInThisContext(`async (${Object.keys(context).join(",")})=>{{${transformed}
81
+ }}`, {
82
+ filename: fsPath,
83
+ lineOffset: 0
84
+ });
85
+ await fn(...Object.values(context));
86
+ return exports;
87
+ }
88
+ prepareContext(context) {
89
+ return context;
90
+ }
91
+ setCache(id, mod) {
92
+ if (!this.moduleCache.has(id))
93
+ this.moduleCache.set(id, mod);
94
+ else
95
+ Object.assign(this.moduleCache.get(id), mod);
96
+ }
97
+ }
98
+ function hasNestedDefault(target) {
99
+ return "__esModule" in target && target.__esModule && "default" in target.default;
100
+ }
101
+ function proxyMethod(name, tryDefault) {
102
+ return function(target, key, ...args) {
103
+ const result = Reflect[name](target, key, ...args);
104
+ if (isPrimitive(target.default))
105
+ return result;
106
+ if (tryDefault && key === "default" || typeof result === "undefined")
107
+ return Reflect[name](target.default, key, ...args);
108
+ return result;
109
+ };
110
+ }
111
+ async function interpretedImport(path, interpretDefault) {
112
+ const mod = await import(path);
113
+ if (interpretDefault && "default" in mod) {
114
+ const tryDefault = hasNestedDefault(mod);
115
+ return new Proxy(mod, {
116
+ get: proxyMethod("get", tryDefault),
117
+ set: proxyMethod("set", tryDefault),
118
+ has: proxyMethod("has", tryDefault),
119
+ deleteProperty: proxyMethod("deleteProperty", tryDefault)
120
+ });
121
+ }
122
+ return mod;
123
+ }
124
+ function exportAll(exports, sourceModule) {
125
+ for (const key in sourceModule) {
126
+ if (key !== "default") {
127
+ try {
128
+ Object.defineProperty(exports, key, {
129
+ enumerable: true,
130
+ configurable: true,
131
+ get() {
132
+ return sourceModule[key];
133
+ }
134
+ });
135
+ } catch (_err) {
136
+ }
137
+ }
138
+ }
139
+ }
140
+
141
+ export { ViteNodeRunner };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+
package/dist/server.js ADDED
@@ -0,0 +1,154 @@
1
+ import { existsSync } from 'fs';
2
+ import { isNodeBuiltin, isValidNodeImport } from 'mlly';
3
+ import { slash, toFilePath } from './utils.js';
4
+ import 'url';
5
+ import 'pathe';
6
+
7
+ const ESM_EXT_RE = /\.(es|esm|esm-browser|esm-bundler|es6|module)\.js$/;
8
+ const ESM_FOLDER_RE = /\/esm\/(.*\.js)$/;
9
+ const defaultInline = [
10
+ /\/vitest\/dist\//,
11
+ /vitest-virtual-\w+\/dist/,
12
+ /virtual:/,
13
+ /\.ts$/,
14
+ ESM_EXT_RE,
15
+ ESM_FOLDER_RE
16
+ ];
17
+ const depsExternal = [
18
+ /\.cjs.js$/,
19
+ /\.mjs$/
20
+ ];
21
+ function guessCJSversion(id) {
22
+ if (id.match(ESM_EXT_RE)) {
23
+ for (const i of [
24
+ id.replace(ESM_EXT_RE, ".mjs"),
25
+ id.replace(ESM_EXT_RE, ".umd.js"),
26
+ id.replace(ESM_EXT_RE, ".cjs.js"),
27
+ id.replace(ESM_EXT_RE, ".js")
28
+ ]) {
29
+ if (existsSync(i))
30
+ return i;
31
+ }
32
+ }
33
+ if (id.match(ESM_FOLDER_RE)) {
34
+ for (const i of [
35
+ id.replace(ESM_FOLDER_RE, "/umd/$1"),
36
+ id.replace(ESM_FOLDER_RE, "/cjs/$1"),
37
+ id.replace(ESM_FOLDER_RE, "/$1")
38
+ ]) {
39
+ if (existsSync(i))
40
+ return i;
41
+ }
42
+ }
43
+ }
44
+ async function shouldExternalize(id, config, cache = new Map()) {
45
+ if (!cache.has(id))
46
+ cache.set(id, _shouldExternalize(id, config));
47
+ return cache.get(id);
48
+ }
49
+ async function _shouldExternalize(id, config) {
50
+ if (isNodeBuiltin(id))
51
+ return id;
52
+ id = patchWindowsImportPath(id);
53
+ if (matchExternalizePattern(id, config == null ? void 0 : config.inline))
54
+ return false;
55
+ if (matchExternalizePattern(id, config == null ? void 0 : config.external))
56
+ return id;
57
+ const isNodeModule = id.includes("/node_modules/");
58
+ id = isNodeModule ? guessCJSversion(id) || id : id;
59
+ if (matchExternalizePattern(id, defaultInline))
60
+ return false;
61
+ if (matchExternalizePattern(id, depsExternal))
62
+ return id;
63
+ if (isNodeModule && await isValidNodeImport(id))
64
+ return id;
65
+ return false;
66
+ }
67
+ function matchExternalizePattern(id, patterns) {
68
+ if (!patterns)
69
+ return false;
70
+ for (const ex of patterns) {
71
+ if (typeof ex === "string") {
72
+ if (id.includes(`/node_modules/${ex}/`))
73
+ return true;
74
+ } else {
75
+ if (ex.test(id))
76
+ return true;
77
+ }
78
+ }
79
+ return false;
80
+ }
81
+ function patchWindowsImportPath(path) {
82
+ if (path.match(/^\w:\\/))
83
+ return `file:///${slash(path)}`;
84
+ else if (path.match(/^\w:\//))
85
+ return `file:///${path}`;
86
+ else
87
+ return path;
88
+ }
89
+
90
+ let SOURCEMAPPING_URL = "sourceMa";
91
+ SOURCEMAPPING_URL += "ppingURL";
92
+ class ViteNodeServer {
93
+ constructor(server, options = {}) {
94
+ this.server = server;
95
+ this.options = options;
96
+ this.promiseMap = new Map();
97
+ }
98
+ shouldExternalize(id) {
99
+ return shouldExternalize(id, this.options.deps);
100
+ }
101
+ async fetchModule(id) {
102
+ const externalize = await this.shouldExternalize(toFilePath(id, this.server.config.root));
103
+ if (externalize)
104
+ return { externalize };
105
+ const r = await this.transformRequest(id);
106
+ return { code: r == null ? void 0 : r.code };
107
+ }
108
+ async transformRequest(id) {
109
+ if (!this.promiseMap.has(id)) {
110
+ this.promiseMap.set(id, this._transformRequest(id).finally(() => {
111
+ this.promiseMap.delete(id);
112
+ }));
113
+ }
114
+ return this.promiseMap.get(id);
115
+ }
116
+ getTransformMode(id) {
117
+ var _a, _b, _c, _d;
118
+ const withoutQuery = id.split("?")[0];
119
+ if ((_b = (_a = this.options.transformMode) == null ? void 0 : _a.web) == null ? void 0 : _b.some((r) => withoutQuery.match(r)))
120
+ return "web";
121
+ if ((_d = (_c = this.options.transformMode) == null ? void 0 : _c.ssr) == null ? void 0 : _d.some((r) => withoutQuery.match(r)))
122
+ return "ssr";
123
+ if (withoutQuery.match(/\.([cm]?[jt]sx?|json)$/))
124
+ return "ssr";
125
+ return "web";
126
+ }
127
+ async _transformRequest(id) {
128
+ let result = null;
129
+ const mode = this.getTransformMode(id);
130
+ if (mode === "web") {
131
+ result = await this.server.transformRequest(id);
132
+ if (result)
133
+ result = await this.server.ssrTransform(result.code, result.map, id);
134
+ } else {
135
+ result = await this.server.transformRequest(id, { ssr: true });
136
+ }
137
+ if (result && !id.includes("node_modules"))
138
+ withInlineSourcemap(result);
139
+ return result;
140
+ }
141
+ }
142
+ async function withInlineSourcemap(result) {
143
+ const { code, map } = result;
144
+ if (code.includes(`${SOURCEMAPPING_URL}=`))
145
+ return result;
146
+ if (map)
147
+ result.code = `${code}
148
+
149
+ //# ${SOURCEMAPPING_URL}=data:application/json;charset=utf-8;base64,${Buffer.from(JSON.stringify(map), "utf-8").toString("base64")}
150
+ `;
151
+ return result;
152
+ }
153
+
154
+ export { ViteNodeServer, guessCJSversion, shouldExternalize, withInlineSourcemap };
package/dist/utils.js ADDED
@@ -0,0 +1,23 @@
1
+ import { fileURLToPath, pathToFileURL } from 'url';
2
+ import { dirname, resolve } from 'pathe';
3
+
4
+ const isWindows = process.platform === "win32";
5
+ function slash(str) {
6
+ return str.replace(/\\/g, "/");
7
+ }
8
+ function normalizeId(id, base) {
9
+ if (base && id.startsWith(base))
10
+ id = `/${id.slice(base.length)}`;
11
+ return id.replace(/^\/@id\/__x00__/, "\0").replace(/^\/@id\//, "").replace(/^__vite-browser-external:/, "").replace(/^node:/, "").replace(/[?&]v=\w+/, "?").replace(/\?$/, "");
12
+ }
13
+ function isPrimitive(v) {
14
+ return v !== Object(v);
15
+ }
16
+ function toFilePath(id, root) {
17
+ let absolute = slash(id).startsWith("/@fs/") ? id.slice(4) : id.startsWith(dirname(root)) ? id : id.startsWith("/") ? slash(resolve(root, id.slice(1))) : id;
18
+ if (absolute.startsWith("//"))
19
+ absolute = absolute.slice(1);
20
+ return isWindows && absolute.startsWith("/") ? fileURLToPath(pathToFileURL(absolute.slice(1)).href) : absolute;
21
+ }
22
+
23
+ export { isPrimitive, isWindows, normalizeId, slash, toFilePath };
package/index.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ interface ExternalizeOptions {
2
+ external?: (string | RegExp)[];
3
+ inline?: (string | RegExp)[];
4
+ fallbackCJS?: boolean;
5
+ }
6
+ declare type FetchFunction = (id: string) => Promise<{
7
+ code?: string;
8
+ externalize?: string;
9
+ }>;
10
+ interface ModuleCache {
11
+ promise?: Promise<any>;
12
+ exports?: any;
13
+ code?: string;
14
+ }
15
+ interface ViteNodeRunnerOptions {
16
+ fetchModule: FetchFunction;
17
+ root: string;
18
+ base?: string;
19
+ moduleCache?: Map<string, ModuleCache>;
20
+ interpretDefault?: boolean;
21
+ requestStubs?: Record<string, any>;
22
+ }
23
+ interface ViteNodeServerOptions {
24
+ deps?: ExternalizeOptions;
25
+ transformMode?: {
26
+ ssr?: RegExp[];
27
+ web?: RegExp[];
28
+ };
29
+ }
30
+
31
+ export { ExternalizeOptions, FetchFunction, ModuleCache, ViteNodeRunnerOptions, ViteNodeServerOptions };
package/package.json CHANGED
@@ -1,67 +1,67 @@
1
1
  {
2
2
  "name": "vite-node",
3
- "version": "0.1.11",
4
- "description": "Vite as Node runtime",
5
- "keywords": [
6
- "vite"
7
- ],
8
- "homepage": "https://github.com/antfu/vite-node#readme",
3
+ "version": "0.1.17",
4
+ "description": "Vite as Node.js runtime",
5
+ "homepage": "https://github.com/vitest-dev/vitest#readme",
9
6
  "bugs": {
10
- "url": "https://github.com/antfu/vite-node/issues"
7
+ "url": "https://github.com/vitest-dev/vitest/issues"
11
8
  },
12
9
  "repository": {
13
10
  "type": "git",
14
- "url": "git+https://github.com/antfu/vite-node.git"
11
+ "url": "git+https://github.com/vitest-dev/vitest.git",
12
+ "directory": "packages/vite-node"
15
13
  },
16
14
  "funding": "https://github.com/sponsors/antfu",
17
15
  "license": "MIT",
18
16
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
19
- "sideEffects": false,
20
17
  "type": "module",
21
18
  "exports": {
22
19
  ".": {
23
- "import": "./index.mjs",
20
+ "import": "./dist/index.js",
24
21
  "types": "./index.d.ts"
25
22
  },
26
- "./cli": {
27
- "import": "./cli.mjs"
23
+ "./client": {
24
+ "import": "./dist/client.js",
25
+ "types": "./client.d.ts"
26
+ },
27
+ "./server": {
28
+ "import": "./dist/server.js",
29
+ "types": "./server.d.ts"
30
+ },
31
+ "./utils": {
32
+ "import": "./dist/utils.js",
33
+ "types": "./utils.d.ts"
28
34
  }
29
35
  },
30
- "main": "./index.mjs",
31
- "module": "./index.mjs",
36
+ "main": "./dist/index.js",
37
+ "module": "./dist/index.js",
32
38
  "types": "./index.d.ts",
33
39
  "bin": {
34
40
  "vite-node": "./vite-node.mjs"
35
41
  },
36
42
  "files": [
43
+ "dist",
44
+ "*.d.ts",
37
45
  "*.mjs"
38
46
  ],
39
47
  "dependencies": {
40
- "debug": "^4.3.3",
41
- "kolorist": "^1.5.0",
48
+ "kolorist": "^1.5.1",
42
49
  "minimist": "^1.2.5",
43
- "vite": "^2.6.5"
50
+ "mlly": "^0.3.17",
51
+ "pathe": "^0.2.0",
52
+ "vite": "^2.7.12"
44
53
  },
45
54
  "devDependencies": {
46
- "@antfu/eslint-config": "^0.11.1",
47
- "@antfu/ni": "^0.11.0",
48
- "@types/debug": "^4.1.7",
49
- "@types/node": "^16.11.11",
50
- "@vitejs/plugin-vue": "^1.10.1",
51
- "bumpp": "^7.1.1",
52
- "eslint": "^8.3.0",
53
- "esno": "^0.12.1",
54
- "typescript": "^4.5.2",
55
- "uvu": "^0.5.2",
56
- "vue": "^3.2.23"
55
+ "@types/minimist": "^1.2.2",
56
+ "rollup": "^2.63.0"
57
57
  },
58
58
  "engines": {
59
- "node": ">=14.0.0"
59
+ "node": ">=14.14.0"
60
60
  },
61
61
  "scripts": {
62
- "lint": "eslint \"**/*.{ts,mjs}\"",
63
- "release": "bumpp --commit --push --tag && pnpm publish",
64
- "start": "DEBUG=vite-node:* node cli.mjs",
65
- "test": "node cli.mjs -c test/vite.config.ts --vue test/index.test.mjs"
66
- }
62
+ "build": "rimraf dist && rollup -c",
63
+ "dev": "rollup -c --watch --watch.include=src/**",
64
+ "typecheck": "tsc --noEmit"
65
+ },
66
+ "readme": "# vite-node\n\n[![NPM version](https://img.shields.io/npm/v/vite-node?color=a1b858&label=)](https://www.npmjs.com/package/vite-node)\n\nVite as Node runtime. The engine powers [Vitest](https://github.com/vitest-dev/vitest).\n\n## Features\n\n- Out-of-box ESM & TypeScript support (possible for more with plugins)\n- Top-level await\n- Vite plugins, resolve, aliasing\n- Respect `vite.config.ts`\n- Shims for `__dirname` and `__filename` in ESM\n- Access to native node modules like `fs`, `path`, etc.\n\n## CLI Usage\n\nRun JS/TS file on Node.js using Vite's resolvers and transformers.\n\n```bash\nnpx vite-node index.ts\n```\n\nOptions:\n\n```bash\nnpx vite-node -h\n```\n\n## Programmatic Usage\n\nIn Vite Node, the server and runner (client) are separated, so you can integrate them in different contexts (workers, cross-process, or remote) if needed. The demo below shows a simple example of having the server and running in the same context\n\n```ts\nimport { createServer } from 'vite'\nimport { ViteNodeServer } from 'vite-node/server'\nimport { ViteNodeRunner } from 'vite-node/client'\n\n// create vite server\nconst server = await createServer()\n// this is need to initialize the plugins\nawait server.pluginContainer.buildStart({})\n\n// create vite-node server\nconst node = new ViteNodeServer(server)\n\n// create vite-node runner\nconst runner = new ViteNodeRunner({\n root: server.config.root,\n base: server.config.base,\n // when having the server and runner in a different context,\n // you will need to handle the communication between them\n // and pass to this function\n fetchModule(id) {\n return node.fetchModule(id)\n },\n})\n\n// execute the file\nawait runner.executeFile('./example.ts')\n\n// close the vite server\nawait server.close()\n```\n\n## Credits\n\nBased on [@pi0](https://github.com/pi0)'s brilliant idea of having a Vite server as the on-demand transforming service for [Nuxt's Vite SSR](https://github.com/nuxt/vite/pull/201).\n\nThanks [@brillout](https://github.com/brillout) for kindly sharing this package name.\n\n## Sponsors\n\n<p align=\"center\">\n <a href=\"https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg\">\n <img src='https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg'/>\n </a>\n</p>\n\n## License\n\n[MIT](./LICENSE) License © 2021 [Anthony Fu](https://github.com/antfu)\n"
67
67
  }
package/server.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import { ViteDevServer, TransformResult } from 'vite';
2
+
3
+ interface ExternalizeOptions {
4
+ external?: (string | RegExp)[];
5
+ inline?: (string | RegExp)[];
6
+ fallbackCJS?: boolean;
7
+ }
8
+ interface ViteNodeServerOptions {
9
+ deps?: ExternalizeOptions;
10
+ transformMode?: {
11
+ ssr?: RegExp[];
12
+ web?: RegExp[];
13
+ };
14
+ }
15
+
16
+ declare function guessCJSversion(id: string): string | undefined;
17
+ declare function shouldExternalize(id: string, config?: ExternalizeOptions, cache?: Map<string, Promise<string | false>>): Promise<string | false>;
18
+
19
+ declare class ViteNodeServer {
20
+ server: ViteDevServer;
21
+ options: ViteNodeServerOptions;
22
+ promiseMap: Map<string, Promise<TransformResult | null | undefined>>;
23
+ constructor(server: ViteDevServer, options?: ViteNodeServerOptions);
24
+ shouldExternalize(id: string): Promise<string | false>;
25
+ fetchModule(id: string): Promise<{
26
+ externalize: string;
27
+ code?: undefined;
28
+ } | {
29
+ code: string | undefined;
30
+ externalize?: undefined;
31
+ }>;
32
+ transformRequest(id: string): Promise<TransformResult | null | undefined>;
33
+ private getTransformMode;
34
+ private _transformRequest;
35
+ }
36
+ declare function withInlineSourcemap(result: TransformResult): Promise<TransformResult>;
37
+
38
+ export { ViteNodeServer, guessCJSversion, shouldExternalize, withInlineSourcemap };
package/utils.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ declare const isWindows: boolean;
2
+ declare function slash(str: string): string;
3
+ declare function normalizeId(id: string, base?: string): string;
4
+ declare function isPrimitive(v: any): boolean;
5
+ declare function toFilePath(id: string, root: string): string;
6
+
7
+ export { isPrimitive, isWindows, normalizeId, slash, toFilePath };
package/vite-node.mjs CHANGED
@@ -1,4 +1,2 @@
1
1
  #!/usr/bin/env node
2
- 'use strict'
3
-
4
- import './cli.mjs'
2
+ import('./dist/cli.js')
package/cli.mjs DELETED
@@ -1,54 +0,0 @@
1
- /* eslint-disable no-console */
2
- import minimist from 'minimist'
3
- import { red, dim } from 'kolorist'
4
- import { run } from './index.mjs'
5
-
6
- const argv = minimist(process.argv.slice(2), {
7
- 'alias': {
8
- r: 'root',
9
- c: 'config',
10
- h: 'help',
11
- w: 'watch',
12
- s: 'silent',
13
- },
14
- '--': true,
15
- 'string': ['root', 'config'],
16
- 'boolean': ['help', 'vue', 'watch', 'silent'],
17
- unknown(name) {
18
- if (name[0] === '-') {
19
- console.error(red(`Unknown argument: ${name}`))
20
- help()
21
- process.exit(1)
22
- }
23
- },
24
- })
25
-
26
- if (argv.help) {
27
- help()
28
- process.exit(0)
29
- }
30
-
31
- if (!argv._.length) {
32
- console.error(red('No files specified.'))
33
- help()
34
- process.exit(1)
35
- }
36
-
37
- // forward argv
38
- process.argv = [process.argv.slice(0, 2), ...argv['--']]
39
-
40
- run(argv)
41
-
42
- function help() {
43
- console.log(`
44
- Usage:
45
- $ vite-node [options] [files]
46
-
47
- Options:
48
- -r, --root <path> ${dim('[string]')} use specified root directory
49
- -c, --config <file> ${dim('[string]')} use specified config file
50
- -w, --watch ${dim('[boolean]')} restart on file changes, similar to "nodemon"
51
- -s, --silent ${dim('[boolean]')} do not emit errors and logs
52
- --vue ${dim('[boolean]')} support for importing Vue component
53
- `)
54
- }
package/index.mjs DELETED
@@ -1,210 +0,0 @@
1
- /* eslint-disable no-console */
2
- import { builtinModules, createRequire } from 'module'
3
- import { pathToFileURL } from 'url'
4
- import { dirname, resolve, relative } from 'path'
5
- import vm from 'vm'
6
- import { createServer, mergeConfig } from 'vite'
7
- import createDebug from 'debug'
8
- import { red, dim, yellow, green, inverse, cyan } from 'kolorist'
9
-
10
- const debugRequest = createDebug('vite-node:request')
11
- const debugTransform = createDebug('vite-node:transform')
12
-
13
- let executing = false
14
-
15
- export async function run(argv) {
16
- process.exitCode = 0
17
- executing = true
18
- let err
19
-
20
- function log(...args) {
21
- if (argv.silent)
22
- return
23
- console.log(...args)
24
- }
25
-
26
- const root = argv.root || process.cwd()
27
- process.chdir(root)
28
-
29
- const files = argv.files || argv._
30
-
31
- const shouldExternalize = argv.shouldExternalize || (id => id.includes('/node_modules/'))
32
-
33
- const server = await createServer(mergeConfig(argv.defaultConfig || {}, {
34
- logLevel: 'error',
35
- clearScreen: false,
36
- configFile: argv.config,
37
- root,
38
- resolve: argv.vue
39
- ? {
40
- alias: {
41
- // fix for Vue does not support mjs yet
42
- 'vue/server-renderer': 'vue/server-renderer',
43
- 'vue/compiler-sfc': 'vue/compiler-sfc',
44
- '@vue/reactivity': '@vue/reactivity/dist/reactivity.cjs.js',
45
- '@vue/shared': '@vue/shared/dist/shared.cjs.js',
46
- 'vue-router': 'vue-router/dist/vue-router.cjs.js',
47
- 'vue': 'vue/dist/vue.cjs.js',
48
- },
49
- }
50
- : {},
51
- }))
52
- await server.pluginContainer.buildStart({})
53
-
54
- process.__vite_node__ = {
55
- server,
56
- }
57
-
58
- async function run() {
59
- try {
60
- await execute(files, server, shouldExternalize)
61
- }
62
- catch (e) {
63
- console.error(e)
64
- err = e
65
- if (!argv.watch)
66
- process.exit(1)
67
- }
68
- finally {
69
- executing = false
70
- }
71
- }
72
-
73
- if (argv.watch) {
74
- log(inverse(cyan(' vite node ')), cyan('watch mode enabled\n'))
75
-
76
- server.watcher.on('change', (file) => {
77
- if (!executing) {
78
- log(inverse(yellow(' vite node ')), yellow(`${file} changed, restarting...\n`))
79
- run()
80
- }
81
- })
82
- }
83
- else {
84
- await run()
85
- }
86
-
87
- if (argv.watch) {
88
- setTimeout(() => {
89
- if (err || process.exitCode)
90
- log(inverse(red(' vite node ')), red('program exited with error, waiting for file changes...'))
91
- else
92
- log(inverse(green(' vite node ')), green('program exited, waiting for file changes...'))
93
- }, 10)
94
- }
95
- else {
96
- await server.close()
97
- }
98
- }
99
-
100
- function normalizeId(id) {
101
- // Virtual modules start with `\0`
102
- if (id && id.startsWith('/@id/__x00__'))
103
- id = `\0${id.slice('/@id/__x00__'.length)}`
104
- if (id && id.startsWith('/@id/'))
105
- id = id.slice('/@id/'.length)
106
- return id
107
- }
108
-
109
- function toFilePath(id, server) {
110
- let absolute = id.startsWith('/@fs/')
111
- ? id.slice(4)
112
- : id.startsWith(dirname(server.config.root))
113
- ? id
114
- : slash(resolve(server.config.root, id.slice(1)))
115
-
116
- if (absolute.startsWith('//'))
117
- absolute = absolute.slice(1)
118
- if (!absolute.startsWith('/'))
119
- absolute = `/${absolute}`
120
-
121
- return absolute
122
- }
123
-
124
- async function execute(files, server, shouldExternalize) {
125
- const __pendingModules__ = new Map()
126
-
127
- const result = []
128
- for (const file of files)
129
- result.push(await cachedRequest(`/@fs/${slash(resolve(file))}`, []))
130
- return result
131
-
132
- async function directRequest(rawId, callstack) {
133
- if (builtinModules.includes(rawId))
134
- return import(rawId)
135
-
136
- callstack = [...callstack, rawId]
137
- const request = async(dep) => {
138
- if (callstack.includes(dep)) {
139
- throw new Error(`${red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => {
140
- const path = relative(server.config.root, toFilePath(normalizeId(i), server))
141
- return dim(' -> ') + (i === dep ? yellow(path) : path)
142
- }).join('\n')}\n`)
143
- }
144
- return cachedRequest(dep, callstack)
145
- }
146
-
147
- const id = normalizeId(rawId)
148
- const absolute = toFilePath(id, server)
149
-
150
- debugRequest(absolute)
151
-
152
- if (shouldExternalize(absolute))
153
- return import(absolute)
154
-
155
- const result = await server.transformRequest(id, { ssr: true })
156
- if (!result)
157
- throw new Error(`failed to load ${id}`)
158
-
159
- debugTransform(id, result.code)
160
-
161
- const url = pathToFileURL(absolute)
162
- const exports = {}
163
-
164
- const context = {
165
- require: createRequire(url),
166
- __filename: absolute,
167
- __dirname: dirname(absolute),
168
- __vite_ssr_import__: request,
169
- __vite_ssr_dynamic_import__: request,
170
- __vite_ssr_exports__: exports,
171
- __vite_ssr_exportAll__: obj => exportAll(exports, obj),
172
- __vite_ssr_import_meta__: { url },
173
- }
174
-
175
- const fn = vm.runInThisContext(`async (${Object.keys(context).join(',')}) => { ${result.code} }`, {
176
- filename: absolute,
177
- lineOffset: 0,
178
- })
179
- await fn(...Object.values(context))
180
-
181
- return exports
182
- }
183
-
184
- async function cachedRequest(id, callstack) {
185
- if (__pendingModules__[id])
186
- return __pendingModules__[id]
187
- __pendingModules__[id] = directRequest(id, callstack)
188
- return await __pendingModules__[id]
189
- }
190
-
191
- function exportAll(exports, sourceModule) {
192
- // eslint-disable-next-line no-restricted-syntax
193
- for (const key in sourceModule) {
194
- if (key !== 'default') {
195
- try {
196
- Object.defineProperty(exports, key, {
197
- enumerable: true,
198
- configurable: true,
199
- get() { return sourceModule[key] },
200
- })
201
- }
202
- catch (_err) { }
203
- }
204
- }
205
- }
206
- }
207
-
208
- function slash(path) {
209
- return path.replace(/\\/g, '/')
210
- }