vite-node 0.0.4 → 0.0.142

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,37 +2,66 @@
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
8
 
9
- ## Why?
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.
10
15
 
11
- It runs Vite's id resolving, module transforming, and most importantly, the powerful plugins system!
16
+ ## CLI Usage
12
17
 
13
- ## Usage
18
+ Run JS/TS file on Node.js using Vite's resolvers and transformers.
14
19
 
15
20
  ```bash
16
21
  npx vite-node index.ts
17
22
  ```
18
23
 
19
- ## Features
24
+ Options:
20
25
 
21
- - Out-of-box ESM & TypeScript support (possible for more with plugins)
22
- - Top-level await
23
- - Shims for `__dirname` and `__filename`
24
- - Respect `vite.config.ts`
25
- - Access to node modules like `fs`, `path` etc.
26
+ ```bash
27
+ npx vite-node -h
28
+ ```
29
+
30
+ ## Programmatic Usage
31
+
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
26
33
 
27
- ## 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'
28
38
 
29
- - Production, yet - in very early stage, check it later
30
- - Most of the time when other tools can do that job
31
- - We will need to start a Vite server upon each execution, which will have certain overhead. Only use it when you want the exactly same behavior as Vite or the powerful plugins system (for example, testing components that have 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({})
32
43
 
33
- ## How?
44
+ // create vite-node server
45
+ const node = new ViteNodeServer(server)
34
46
 
35
- It fires up a Vite dev server, transforms the requests, and runs them in Node.
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
+ })
58
+
59
+ // execute the file
60
+ await runner.executeFile('./example.ts')
61
+
62
+ // close the vite server
63
+ await server.close()
64
+ ```
36
65
 
37
66
  ## Credits
38
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,155 @@
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).then((r) => {
111
+ this.promiseMap.delete(id);
112
+ return r;
113
+ }));
114
+ }
115
+ return this.promiseMap.get(id);
116
+ }
117
+ getTransformMode(id) {
118
+ var _a, _b, _c, _d;
119
+ const withoutQuery = id.split("?")[0];
120
+ if ((_b = (_a = this.options.transformMode) == null ? void 0 : _a.web) == null ? void 0 : _b.some((r) => withoutQuery.match(r)))
121
+ return "web";
122
+ if ((_d = (_c = this.options.transformMode) == null ? void 0 : _c.ssr) == null ? void 0 : _d.some((r) => withoutQuery.match(r)))
123
+ return "ssr";
124
+ if (withoutQuery.match(/\.([cm]?[jt]sx?|json)$/))
125
+ return "ssr";
126
+ return "web";
127
+ }
128
+ async _transformRequest(id) {
129
+ let result = null;
130
+ const mode = this.getTransformMode(id);
131
+ if (mode === "web") {
132
+ result = await this.server.transformRequest(id);
133
+ if (result)
134
+ result = await this.server.ssrTransform(result.code, result.map, id);
135
+ } else {
136
+ result = await this.server.transformRequest(id, { ssr: true });
137
+ }
138
+ if (result && !id.includes("node_modules"))
139
+ withInlineSourcemap(result);
140
+ return result;
141
+ }
142
+ }
143
+ async function withInlineSourcemap(result) {
144
+ const { code, map } = result;
145
+ if (code.includes(`${SOURCEMAPPING_URL}=`))
146
+ return result;
147
+ if (map)
148
+ result.code = `${code}
149
+
150
+ //# ${SOURCEMAPPING_URL}=data:application/json;charset=utf-8;base64,${Buffer.from(JSON.stringify(map), "utf-8").toString("base64")}
151
+ `;
152
+ return result;
153
+ }
154
+
155
+ 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,63 +1,67 @@
1
1
  {
2
2
  "name": "vite-node",
3
- "version": "0.0.4",
4
- "description": "Vite as Node runtime",
5
- "keywords": [
6
- "vite"
7
- ],
8
- "homepage": "https://github.com/antfu/vite-node#readme",
3
+ "version": "0.0.142",
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",
21
+ "types": "./index.d.ts"
22
+ },
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"
24
34
  }
25
35
  },
26
- "main": "index.mjs",
27
- "module": "index.mjs",
36
+ "main": "./dist/index.js",
37
+ "module": "./dist/index.js",
38
+ "types": "./index.d.ts",
28
39
  "bin": {
29
- "vite-node": "./bin/vite-node.js"
40
+ "vite-node": "./vite-node.js"
30
41
  },
31
42
  "files": [
32
- "index.mjs",
33
- "bin"
43
+ "dist",
44
+ "*.d.ts",
45
+ "*.mjs"
34
46
  ],
35
47
  "dependencies": {
36
- "debug": "^4.3.2",
37
- "kolorist": "^1.5.0",
48
+ "kolorist": "^1.5.1",
38
49
  "minimist": "^1.2.5",
39
- "vite": "^2.6.5"
50
+ "mlly": "^0.3.17",
51
+ "pathe": "^0.2.0",
52
+ "vite": "^2.7.10"
40
53
  },
41
54
  "devDependencies": {
42
- "@antfu/eslint-config": "^0.9.0",
43
- "@antfu/ni": "^0.10.0",
44
- "@types/debug": "^4.1.7",
45
- "@types/node": "^16.10.3",
46
- "@vitejs/plugin-vue": "^1.9.3",
47
- "bumpp": "^7.1.1",
48
- "eslint": "^7.32.0",
49
- "esno": "^0.10.1",
50
- "typescript": "^4.4.3",
51
- "uvu": "^0.5.2",
52
- "vue": "^3.2.20"
55
+ "@types/minimist": "^1.2.2",
56
+ "rollup": "^2.63.0"
53
57
  },
54
58
  "engines": {
55
- "node": ">=14.0.0"
59
+ "node": ">=14.14.0"
56
60
  },
57
61
  "scripts": {
58
- "lint": "eslint \"**/*.{ts,mjs}\"",
59
- "release": "bumpp --commit --push --tag && pnpm publish",
60
- "start": "DEBUG=vite-node:* node index.mjs",
61
- "test": "node index.mjs -c test/vite.config.ts --vue test/index.test.mjs"
62
- }
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"
63
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 ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import('./dist/cli.js')
package/bin/vite-node.js DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict'
3
-
4
- import '../index.mjs'
package/index.mjs DELETED
@@ -1,191 +0,0 @@
1
- import { builtinModules, createRequire } from 'module'
2
- import { pathToFileURL } from 'url'
3
- import { dirname, resolve, relative } from 'path'
4
- import { createServer } from 'vite'
5
- import createDebug from 'debug'
6
- import minimist from 'minimist'
7
- import { red, dim, yellow } from 'kolorist'
8
-
9
- const argv = minimist(process.argv.slice(2), {
10
- alias: {
11
- r: 'root',
12
- c: 'config',
13
- h: 'help',
14
- },
15
- string: ['root', 'config'],
16
- boolean: ['help', 'vue'],
17
- unknown(name) {
18
- if (name[0] === '-') {
19
- console.error(red(`Unknown argument: ${name}`))
20
- help()
21
- process.exit(1)
22
- }
23
- },
24
- })
25
- const files = argv._
26
-
27
- if (argv.help) {
28
- help()
29
- process.exit(0)
30
- }
31
-
32
- if (!argv._.length) {
33
- console.error(red('No files specified.'))
34
- help()
35
- process.exit(1)
36
- }
37
-
38
- const debugRequest = createDebug('vite-node:request')
39
- const debugTransform = createDebug('vite-node:transform')
40
- const AsyncFunction = Object.getPrototypeOf(async() => {}).constructor
41
-
42
- const root = argv.root || process.cwd()
43
- process.chdir(root)
44
-
45
- const server = await createServer({
46
- configFile: argv.config,
47
- root,
48
- resolve: argv.vue
49
- ? {
50
- alias: {
51
- // fix for Vue does not support mjs yet
52
- 'vue/server-renderer': 'vue/server-renderer',
53
- 'vue/compiler-sfc': 'vue/compiler-sfc',
54
- '@vue/reactivity': '@vue/reactivity/dist/reactivity.cjs.js',
55
- '@vue/shared': '@vue/shared/dist/shared.cjs.js',
56
- 'vue-router': 'vue-router/dist/vue-router.cjs.js',
57
- 'vue': 'vue/dist/vue.cjs.js',
58
- },
59
- }
60
- : {},
61
- })
62
- await server.pluginContainer.buildStart({})
63
- await execute(files, server, argv)
64
- await server.close()
65
-
66
- // --- CLI END ---
67
-
68
- function normalizeId(id) {
69
- // Virtual modules start with `\0`
70
- if (id && id.startsWith('/@id/__x00__'))
71
- id = `\0${id.slice('/@id/__x00__'.length)}`
72
- if (id && id.startsWith('/@id/'))
73
- id = id.slice('/@id/'.length)
74
- return id
75
- }
76
-
77
- function toFilePath(id) {
78
- const absolute = id.startsWith('/@fs/')
79
- ? id.slice(4)
80
- : slash(resolve(server.config.root, id.slice(1)))
81
-
82
- return absolute
83
- }
84
-
85
- async function execute(files, server) {
86
- const __pendingModules__ = new Map()
87
-
88
- async function directRequest(rawId, callstack) {
89
- if (builtinModules.includes(rawId))
90
- return import(rawId)
91
-
92
- callstack = [...callstack, rawId]
93
- const request = async(dep) => {
94
- if (callstack.includes(dep)) {
95
- throw new Error(`${red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => {
96
- const path = relative(server.config.root, toFilePath(normalizeId(i)))
97
- return dim(' -> ') + (i === dep ? yellow(path) : path)
98
- }).join('\n')}\n`)
99
- }
100
- return cachedRequest(dep, callstack)
101
- }
102
-
103
- const id = normalizeId(rawId)
104
- const absolute = toFilePath(id)
105
-
106
- debugRequest(absolute)
107
-
108
- // for windows
109
- const unifiedPath = absolute[0] !== '/'
110
- ? `/${absolute}`
111
- : absolute
112
-
113
- if (absolute.includes('/node_modules/'))
114
- return import(unifiedPath)
115
-
116
- const result = await server.transformRequest(id, { ssr: true })
117
- if (!result)
118
- throw new Error(`failed to load ${id}`)
119
-
120
- debugTransform(id, result.code)
121
-
122
- const url = pathToFileURL(unifiedPath)
123
- const exports = {}
124
-
125
- const context = {
126
- require: createRequire(url),
127
- __filename: absolute,
128
- __dirname: dirname(absolute),
129
- __vite_ssr_import__: request,
130
- __vite_ssr_dynamic_import__: request,
131
- __vite_ssr_exports__: exports,
132
- __vite_ssr_exportAll__: obj => exportAll(exports, obj),
133
- __vite_ssr_import_meta__: { url },
134
- }
135
-
136
- const fn = new AsyncFunction(
137
- ...Object.keys(context),
138
- result.code,
139
- )
140
-
141
- // prefetch deps
142
- result.deps.forEach(dep => request(dep))
143
-
144
- await fn(...Object.values(context))
145
- return exports
146
- }
147
-
148
- function cachedRequest(id, callstack) {
149
- if (!__pendingModules__[id])
150
- __pendingModules__[id] = directRequest(id, callstack)
151
- return __pendingModules__[id]
152
- }
153
-
154
- function exportAll(exports, sourceModule) {
155
- // eslint-disable-next-line no-restricted-syntax
156
- for (const key in sourceModule) {
157
- if (key !== 'default') {
158
- try {
159
- Object.defineProperty(exports, key, {
160
- enumerable: true,
161
- configurable: true,
162
- get() { return sourceModule[key] },
163
- })
164
- }
165
- catch (_err) { }
166
- }
167
- }
168
- }
169
-
170
- const result = []
171
- for (const file of files)
172
- result.push(await cachedRequest(`/@fs/${slash(resolve(file))}`, []))
173
- return result
174
- }
175
-
176
- function slash(path) {
177
- return path.replace(/\\/g, '/')
178
- }
179
-
180
- function help() {
181
- // eslint-disable-next-line no-console
182
- console.log(`
183
- Usage:
184
- $ vite-node [options] [files]
185
-
186
- Options:
187
- -r, --root <path> ${dim('[string]')} use specified root directory
188
- -c, --config <file> ${dim('[string]')} use specified config file
189
- --vue ${dim('[boolean]')} support for importing Vue component
190
- `)
191
- }