vite-node 0.0.2 → 0.1.0

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.
Files changed (3) hide show
  1. package/README.md +16 -7
  2. package/index.mjs +122 -34
  3. package/package.json +11 -11
package/README.md CHANGED
@@ -6,9 +6,6 @@ Vite as Node runtime.
6
6
 
7
7
  > **EXPERIMENTAL**
8
8
 
9
- ## Why?
10
-
11
- It runs Vite's id resolving, module transforming, and most importantly, the powerful plugins system!
12
9
 
13
10
  ## Usage
14
11
 
@@ -16,19 +13,31 @@ It runs Vite's id resolving, module transforming, and most importantly, the powe
16
13
  npx vite-node index.ts
17
14
  ```
18
15
 
16
+ Options:
17
+
18
+ ```bash
19
+ npx vite-node -h
20
+ ```
21
+
19
22
  ## Features
20
23
 
21
24
  - Out-of-box ESM & TypeScript support (possible for more with plugins)
22
25
  - Top-level await
23
- - Shims for `__dirname` and `__filename`
26
+ - Vite plugins, resolve, aliasing
24
27
  - Respect `vite.config.ts`
25
- - Access to node modules like `fs`, `path` etc.
28
+ - Shims for `__dirname` and `__filename` in ESM
29
+ - Access to native node modules like `fs`, `path`, etc.
30
+ - Watch mode (like `nodemon`)
26
31
 
27
32
  ## When NOT to Use
28
33
 
29
34
  - 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).
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).
37
+
38
+ ## Why?
39
+
40
+ It runs Vite's id resolving, module transforming, and most importantly, the powerful plugins system!
32
41
 
33
42
  ## How?
34
43
 
package/index.mjs CHANGED
@@ -1,19 +1,22 @@
1
+ /* eslint-disable no-console */
1
2
  import { builtinModules, createRequire } from 'module'
2
3
  import { pathToFileURL } from 'url'
3
- import { join, dirname, resolve } from 'path'
4
+ import { dirname, resolve, relative } from 'path'
4
5
  import { createServer } from 'vite'
5
6
  import createDebug from 'debug'
6
7
  import minimist from 'minimist'
7
- import { red, dim } from 'kolorist'
8
+ import { red, dim, yellow, green, inverse, cyan } from 'kolorist'
8
9
 
9
10
  const argv = minimist(process.argv.slice(2), {
10
11
  alias: {
11
12
  r: 'root',
12
13
  c: 'config',
13
14
  h: 'help',
15
+ w: 'watch',
16
+ s: 'silent',
14
17
  },
15
18
  string: ['root', 'config'],
16
- boolean: ['help', 'vue'],
19
+ boolean: ['help', 'vue', 'watch', 'silent'],
17
20
  unknown(name) {
18
21
  if (name[0] === '-') {
19
22
  console.error(red(`Unknown argument: ${name}`))
@@ -43,6 +46,8 @@ const root = argv.root || process.cwd()
43
46
  process.chdir(root)
44
47
 
45
48
  const server = await createServer({
49
+ logLevel: 'error',
50
+ clearScreen: false,
46
51
  configFile: argv.config,
47
52
  root,
48
53
  resolve: argv.vue
@@ -60,28 +65,95 @@ const server = await createServer({
60
65
  : {},
61
66
  })
62
67
  await server.pluginContainer.buildStart({})
63
- await execute(files, server, argv)
64
- await server.close()
65
- process.exit(process.exitCode || 0)
68
+ let executing = false
69
+
70
+ async function run() {
71
+ process.exitCode = 0
72
+ executing = true
73
+ let err
74
+ try {
75
+ await execute(files, server, argv)
76
+ }
77
+ catch (e) {
78
+ console.error(e)
79
+ err = e
80
+ if (!argv.watch)
81
+ process.exit(1)
82
+ }
83
+ finally {
84
+ executing = false
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
+ if (argv.watch) {
101
+ log(inverse(cyan(' vite node ')), cyan('watch mode enabled\n'))
102
+
103
+ server.watcher.on('change', (file) => {
104
+ if (!executing) {
105
+ log(inverse(yellow(' vite node ')), yellow(`${file} changed, restarting...\n`))
106
+ run()
107
+ }
108
+ })
109
+ }
110
+
111
+ await run(files, server, argv)
66
112
 
67
113
  // --- CLI END ---
68
114
 
115
+ function normalizeId(id) {
116
+ // Virtual modules start with `\0`
117
+ if (id && id.startsWith('/@id/__x00__'))
118
+ id = `\0${id.slice('/@id/__x00__'.length)}`
119
+ if (id && id.startsWith('/@id/'))
120
+ id = id.slice('/@id/'.length)
121
+ return id
122
+ }
123
+
124
+ function toFilePath(id) {
125
+ const absolute = id.startsWith('/@fs/')
126
+ ? id.slice(4)
127
+ : slash(resolve(server.config.root, id.slice(1)))
128
+
129
+ return absolute
130
+ }
131
+
69
132
  async function execute(files, server) {
70
- const cache = {}
133
+ const __pendingModules__ = new Map()
71
134
 
72
- async function request(id) {
73
- // Virtual modules start with `\0`
74
- if (id && id.startsWith('/@id/__x00__'))
75
- id = `\0${id.slice('/@id/__x00__'.length)}`
76
- if (id && id.startsWith('/@id/'))
77
- id = id.slice('/@id/'.length)
135
+ const result = []
136
+ for (const file of files)
137
+ result.push(await cachedRequest(`/@fs/${slash(resolve(file))}`, []))
138
+ return result
78
139
 
79
- if (builtinModules.includes(id))
80
- return import(id)
140
+ async function directRequest(rawId, callstack) {
141
+ if (builtinModules.includes(rawId))
142
+ return import(rawId)
143
+
144
+ callstack = [...callstack, rawId]
145
+ const request = async(dep) => {
146
+ if (callstack.includes(dep)) {
147
+ throw new Error(`${red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => {
148
+ const path = relative(server.config.root, toFilePath(normalizeId(i)))
149
+ return dim(' -> ') + (i === dep ? yellow(path) : path)
150
+ }).join('\n')}\n`)
151
+ }
152
+ return cachedRequest(dep, callstack)
153
+ }
81
154
 
82
- const absolute = id.startsWith('/@fs/')
83
- ? id.slice(3)
84
- : slash(join(server.config.root, id.slice(1)))
155
+ const id = normalizeId(rawId)
156
+ const absolute = toFilePath(id)
85
157
 
86
158
  debugRequest(absolute)
87
159
 
@@ -90,7 +162,7 @@ async function execute(files, server) {
90
162
  ? `/${absolute}`
91
163
  : absolute
92
164
 
93
- if (id.includes('/node_modules/'))
165
+ if (absolute.includes('/node_modules/'))
94
166
  return import(unifiedPath)
95
167
 
96
168
  const result = await server.transformRequest(id, { ssr: true })
@@ -100,17 +172,16 @@ async function execute(files, server) {
100
172
  debugTransform(id, result.code)
101
173
 
102
174
  const url = pathToFileURL(unifiedPath)
103
-
104
175
  const exports = {}
105
176
 
106
177
  const context = {
107
178
  require: createRequire(url),
108
179
  __filename: absolute,
109
180
  __dirname: dirname(absolute),
110
- __vite_ssr_import__: cachedRequest,
111
- __vite_ssr_dynamic_import__: cachedRequest,
181
+ __vite_ssr_import__: request,
182
+ __vite_ssr_dynamic_import__: request,
112
183
  __vite_ssr_exports__: exports,
113
- __vite_ssr_exportAll__: obj => Object.assign(exports, obj),
184
+ __vite_ssr_exportAll__: obj => exportAll(exports, obj),
114
185
  __vite_ssr_import_meta__: { url },
115
186
  }
116
187
 
@@ -120,22 +191,32 @@ async function execute(files, server) {
120
191
  )
121
192
 
122
193
  // prefetch deps
123
- result.deps.forEach(dep => cachedRequest(dep))
124
-
125
194
  await fn(...Object.values(context))
195
+
126
196
  return exports
127
197
  }
128
198
 
129
- function cachedRequest(path) {
130
- if (!cache[path])
131
- cache[path] = request(path)
132
- return cache[path]
199
+ function cachedRequest(id, callstack) {
200
+ if (!__pendingModules__[id])
201
+ __pendingModules__[id] = directRequest(id, callstack)
202
+ return __pendingModules__[id]
133
203
  }
134
204
 
135
- const result = []
136
- for (const file of files)
137
- result.push(await request(`/@fs/${slash(resolve(file))}`))
138
- return result
205
+ function exportAll(exports, sourceModule) {
206
+ // eslint-disable-next-line no-restricted-syntax
207
+ for (const key in sourceModule) {
208
+ if (key !== 'default') {
209
+ try {
210
+ Object.defineProperty(exports, key, {
211
+ enumerable: true,
212
+ configurable: true,
213
+ get() { return sourceModule[key] },
214
+ })
215
+ }
216
+ catch (_err) { }
217
+ }
218
+ }
219
+ }
139
220
  }
140
221
 
141
222
  function slash(path) {
@@ -143,7 +224,6 @@ function slash(path) {
143
224
  }
144
225
 
145
226
  function help() {
146
- // eslint-disable-next-line no-console
147
227
  console.log(`
148
228
  Usage:
149
229
  $ vite-node [options] [files]
@@ -151,6 +231,14 @@ Usage:
151
231
  Options:
152
232
  -r, --root <path> ${dim('[string]')} use specified root directory
153
233
  -c, --config <file> ${dim('[string]')} use specified config file
234
+ -w, --watch ${dim('[boolean]')} restart on file changes, similar to "nodemon"
235
+ -s, --silent ${dim('[boolean]')} do not emit errors and logs
154
236
  --vue ${dim('[boolean]')} support for importing Vue component
155
237
  `)
156
238
  }
239
+
240
+ function log(...args) {
241
+ if (argv.silent)
242
+ return
243
+ console.log(...args)
244
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-node",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "Vite as Node runtime",
5
5
  "keywords": [
6
6
  "vite"
@@ -33,23 +33,23 @@
33
33
  "bin"
34
34
  ],
35
35
  "dependencies": {
36
- "debug": "^4.3.2",
36
+ "debug": "^4.3.3",
37
37
  "kolorist": "^1.5.0",
38
38
  "minimist": "^1.2.5",
39
39
  "vite": "^2.6.5"
40
40
  },
41
41
  "devDependencies": {
42
- "@antfu/eslint-config": "^0.9.0",
43
- "@antfu/ni": "^0.9.3",
42
+ "@antfu/eslint-config": "^0.11.1",
43
+ "@antfu/ni": "^0.11.0",
44
44
  "@types/debug": "^4.1.7",
45
- "@types/node": "^16.10.3",
46
- "@vitejs/plugin-vue": "^1.9.3",
45
+ "@types/node": "^16.11.11",
46
+ "@vitejs/plugin-vue": "^1.10.1",
47
47
  "bumpp": "^7.1.1",
48
- "eslint": "^7.32.0",
49
- "esno": "^0.10.1",
50
- "typescript": "^4.4.3",
51
- "uvu": "^0.5.1",
52
- "vue": "^3.2.20"
48
+ "eslint": "^8.3.0",
49
+ "esno": "^0.12.1",
50
+ "typescript": "^4.5.2",
51
+ "uvu": "^0.5.2",
52
+ "vue": "^3.2.23"
53
53
  },
54
54
  "engines": {
55
55
  "node": ">=14.0.0"