vite 2.6.0-beta.0 → 2.6.0-beta.4

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.

Potentially problematic release.


This version of vite might be problematic. Click here for more details.

Files changed (110) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE.md +161 -3011
  3. package/bin/vite.js +2 -1
  4. package/dist/node/chunks/{dep-91aa74e8.js → dep-1e0a75a8.js} +58 -32
  5. package/dist/node/chunks/dep-1e0a75a8.js.map +1 -0
  6. package/dist/node/chunks/{dep-e36486f6.js → dep-ac1b4bf9.js} +1 -1
  7. package/dist/node/chunks/dep-ac1b4bf9.js.map +1 -0
  8. package/dist/node/chunks/{dep-c7e510f9.js → dep-ba6b30a0.js} +27538 -4953
  9. package/dist/node/chunks/dep-ba6b30a0.js.map +1 -0
  10. package/dist/node/chunks/{dep-11213a75.js → dep-c4cf6e92.js} +19 -6
  11. package/dist/node/chunks/dep-c4cf6e92.js.map +1 -0
  12. package/dist/node/chunks/{dep-eb6ef720.js → dep-d574094c.js} +18 -5
  13. package/dist/node/chunks/dep-d574094c.js.map +1 -0
  14. package/dist/node/chunks/{dep-0d2f9464.js → dep-e39b05d6.js} +18 -5
  15. package/dist/node/chunks/dep-e39b05d6.js.map +1 -0
  16. package/dist/node/cli.js +60 -23992
  17. package/dist/node/cli.js.map +1 -1
  18. package/dist/node/index.d.ts +26 -8
  19. package/dist/node/index.js +18 -15
  20. package/dist/node/index.js.map +1 -1
  21. package/dist/node/terser.js +102 -55
  22. package/package.json +28 -13
  23. package/types/package.json +3 -0
  24. package/api-extractor.json +0 -54
  25. package/dist/node/chunks/dep-0d2f9464.js.map +0 -1
  26. package/dist/node/chunks/dep-11213a75.js.map +0 -1
  27. package/dist/node/chunks/dep-91aa74e8.js.map +0 -1
  28. package/dist/node/chunks/dep-c7e510f9.js.map +0 -1
  29. package/dist/node/chunks/dep-e36486f6.js.map +0 -1
  30. package/dist/node/chunks/dep-eb6ef720.js.map +0 -1
  31. package/dist/node/terser.js.map +0 -1
  32. package/rollup.config.js +0 -389
  33. package/scripts/patchTypes.js +0 -70
  34. package/src/node/__tests__/asset.spec.ts +0 -156
  35. package/src/node/__tests__/build.spec.ts +0 -67
  36. package/src/node/__tests__/config.spec.ts +0 -166
  37. package/src/node/__tests__/packages/name/package.json +0 -3
  38. package/src/node/__tests__/packages/noname/package.json +0 -1
  39. package/src/node/__tests__/plugins/css.spec.ts +0 -116
  40. package/src/node/__tests__/scan.spec.ts +0 -118
  41. package/src/node/__tests__/utils.spec.ts +0 -40
  42. package/src/node/build.ts +0 -783
  43. package/src/node/cli.ts +0 -239
  44. package/src/node/config.ts +0 -1033
  45. package/src/node/constants.ts +0 -87
  46. package/src/node/importGlob.ts +0 -173
  47. package/src/node/index.ts +0 -88
  48. package/src/node/logger.ts +0 -167
  49. package/src/node/optimizer/esbuildDepPlugin.ts +0 -216
  50. package/src/node/optimizer/index.ts +0 -410
  51. package/src/node/optimizer/registerMissing.ts +0 -102
  52. package/src/node/optimizer/scan.ts +0 -457
  53. package/src/node/plugin.ts +0 -138
  54. package/src/node/plugins/asset.ts +0 -365
  55. package/src/node/plugins/assetImportMetaUrl.ts +0 -99
  56. package/src/node/plugins/clientInjections.ts +0 -72
  57. package/src/node/plugins/css.ts +0 -1279
  58. package/src/node/plugins/dataUri.ts +0 -64
  59. package/src/node/plugins/define.ts +0 -107
  60. package/src/node/plugins/esbuild.ts +0 -280
  61. package/src/node/plugins/html.ts +0 -673
  62. package/src/node/plugins/importAnalysis.ts +0 -614
  63. package/src/node/plugins/importAnalysisBuild.ts +0 -334
  64. package/src/node/plugins/index.ts +0 -69
  65. package/src/node/plugins/json.ts +0 -75
  66. package/src/node/plugins/loadFallback.ts +0 -19
  67. package/src/node/plugins/manifest.ts +0 -123
  68. package/src/node/plugins/modulePreloadPolyfill.ts +0 -100
  69. package/src/node/plugins/preAlias.ts +0 -22
  70. package/src/node/plugins/reporter.ts +0 -244
  71. package/src/node/plugins/resolve.ts +0 -925
  72. package/src/node/plugins/terser.ts +0 -40
  73. package/src/node/plugins/wasm.ts +0 -72
  74. package/src/node/plugins/worker.ts +0 -117
  75. package/src/node/preview.ts +0 -82
  76. package/src/node/server/__tests__/fixtures/none/nested/package.json +0 -3
  77. package/src/node/server/__tests__/fixtures/pnpm/nested/package.json +0 -3
  78. package/src/node/server/__tests__/fixtures/pnpm/package.json +0 -3
  79. package/src/node/server/__tests__/fixtures/pnpm/pnpm-workspace.yaml +0 -0
  80. package/src/node/server/__tests__/fixtures/yarn/nested/package.json +0 -3
  81. package/src/node/server/__tests__/fixtures/yarn/package.json +0 -6
  82. package/src/node/server/__tests__/search-root.spec.ts +0 -31
  83. package/src/node/server/hmr.ts +0 -489
  84. package/src/node/server/http.ts +0 -198
  85. package/src/node/server/index.ts +0 -705
  86. package/src/node/server/middlewares/base.ts +0 -52
  87. package/src/node/server/middlewares/error.ts +0 -98
  88. package/src/node/server/middlewares/indexHtml.ts +0 -170
  89. package/src/node/server/middlewares/proxy.ts +0 -124
  90. package/src/node/server/middlewares/spaFallback.ts +0 -32
  91. package/src/node/server/middlewares/static.ts +0 -153
  92. package/src/node/server/middlewares/time.ts +0 -18
  93. package/src/node/server/middlewares/transform.ts +0 -196
  94. package/src/node/server/moduleGraph.ts +0 -200
  95. package/src/node/server/openBrowser.ts +0 -101
  96. package/src/node/server/pluginContainer.ts +0 -546
  97. package/src/node/server/searchRoot.ts +0 -70
  98. package/src/node/server/send.ts +0 -54
  99. package/src/node/server/sourcemap.ts +0 -54
  100. package/src/node/server/transformRequest.ts +0 -168
  101. package/src/node/server/ws.ts +0 -131
  102. package/src/node/ssr/__tests__/ssrTransform.spec.ts +0 -309
  103. package/src/node/ssr/ssrExternal.ts +0 -161
  104. package/src/node/ssr/ssrManifestPlugin.ts +0 -53
  105. package/src/node/ssr/ssrModuleLoader.ts +0 -214
  106. package/src/node/ssr/ssrStacktrace.ts +0 -75
  107. package/src/node/ssr/ssrTransform.ts +0 -452
  108. package/src/node/tsconfig.json +0 -14
  109. package/src/node/utils.ts +0 -565
  110. package/tsconfig.base.json +0 -11
@@ -1,1279 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import glob from 'fast-glob'
4
- import {
5
- // createDebugger,
6
- isExternalUrl,
7
- asyncReplace,
8
- cleanUrl,
9
- generateCodeFrame,
10
- isDataUrl,
11
- isObject,
12
- normalizePath,
13
- processSrcSet
14
- } from '../utils'
15
- import { Plugin } from '../plugin'
16
- import { ResolvedConfig } from '../config'
17
- import postcssrc from 'postcss-load-config'
18
- import {
19
- NormalizedOutputOptions,
20
- OutputChunk,
21
- RenderedChunk,
22
- RollupError,
23
- SourceMap
24
- } from 'rollup'
25
- import { dataToEsm } from '@rollup/pluginutils'
26
- import chalk from 'chalk'
27
- import { CLIENT_PUBLIC_PATH } from '../constants'
28
- import { ResolveFn, ViteDevServer } from '../'
29
- import {
30
- getAssetFilename,
31
- assetUrlRE,
32
- registerAssetToChunk,
33
- fileToUrl,
34
- checkPublicFile
35
- } from './asset'
36
- import MagicString from 'magic-string'
37
- import * as Postcss from 'postcss'
38
- import type Sass from 'sass'
39
- // We need to disable check of extraneous import which is buggy for stylus,
40
- // and causes the CI tests fail, see: https://github.com/vitejs/vite/pull/2860
41
- import type Stylus from 'stylus' // eslint-disable-line node/no-extraneous-import
42
- import type Less from 'less'
43
- import { Alias } from 'types/alias'
44
- import type { ModuleNode } from '../server/moduleGraph'
45
- import { transform, formatMessages } from 'esbuild'
46
-
47
- // const debug = createDebugger('vite:css')
48
-
49
- export interface CSSOptions {
50
- /**
51
- * https://github.com/css-modules/postcss-modules
52
- */
53
- modules?: CSSModulesOptions | false
54
- preprocessorOptions?: Record<string, any>
55
- postcss?:
56
- | string
57
- | (Postcss.ProcessOptions & {
58
- plugins?: Postcss.Plugin[]
59
- })
60
- }
61
-
62
- export interface CSSModulesOptions {
63
- getJSON?: (
64
- cssFileName: string,
65
- json: Record<string, string>,
66
- outputFileName: string
67
- ) => void
68
- scopeBehaviour?: 'global' | 'local'
69
- globalModulePaths?: RegExp[]
70
- generateScopedName?:
71
- | string
72
- | ((name: string, filename: string, css: string) => string)
73
- hashPrefix?: string
74
- /**
75
- * default: null
76
- */
77
- localsConvention?:
78
- | 'camelCase'
79
- | 'camelCaseOnly'
80
- | 'dashes'
81
- | 'dashesOnly'
82
- | null
83
- }
84
-
85
- const cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)`
86
- const cssLangRE = new RegExp(cssLangs)
87
- const cssModuleRE = new RegExp(`\\.module${cssLangs}`)
88
- const directRequestRE = /(\?|&)direct\b/
89
- const commonjsProxyRE = /\?commonjs-proxy/
90
- const inlineRE = /(\?|&)inline\b/
91
- const usedRE = /(\?|&)used\b/
92
-
93
- const enum PreprocessLang {
94
- less = 'less',
95
- sass = 'sass',
96
- scss = 'scss',
97
- styl = 'styl',
98
- stylus = 'stylus'
99
- }
100
- const enum PureCssLang {
101
- css = 'css'
102
- }
103
- type CssLang = keyof typeof PureCssLang | keyof typeof PreprocessLang
104
-
105
- export const isCSSRequest = (request: string): boolean =>
106
- cssLangRE.test(request)
107
-
108
- export const isDirectCSSRequest = (request: string): boolean =>
109
- cssLangRE.test(request) && directRequestRE.test(request)
110
-
111
- export const isDirectRequest = (request: string): boolean =>
112
- directRequestRE.test(request)
113
-
114
- const cssModulesCache = new WeakMap<
115
- ResolvedConfig,
116
- Map<string, Record<string, string>>
117
- >()
118
-
119
- export const chunkToEmittedCssFileMap = new WeakMap<
120
- RenderedChunk,
121
- Set<string>
122
- >()
123
-
124
- export const removedPureCssFilesCache = new WeakMap<
125
- ResolvedConfig,
126
- Map<string, RenderedChunk>
127
- >()
128
-
129
- const postcssConfigCache = new WeakMap<
130
- ResolvedConfig,
131
- PostCSSConfigResult | null
132
- >()
133
-
134
- /**
135
- * Plugin applied before user plugins
136
- */
137
- export function cssPlugin(config: ResolvedConfig): Plugin {
138
- let server: ViteDevServer
139
- let moduleCache: Map<string, Record<string, string>>
140
-
141
- const resolveUrl = config.createResolver({
142
- preferRelative: true,
143
- tryIndex: false,
144
- extensions: []
145
- })
146
- const atImportResolvers = createCSSResolvers(config)
147
-
148
- return {
149
- name: 'vite:css',
150
-
151
- configureServer(_server) {
152
- server = _server
153
- },
154
-
155
- buildStart() {
156
- // Ensure a new cache for every build (i.e. rebuilding in watch mode)
157
- moduleCache = new Map<string, Record<string, string>>()
158
- cssModulesCache.set(config, moduleCache)
159
-
160
- removedPureCssFilesCache.set(config, new Map<string, RenderedChunk>())
161
- },
162
-
163
- async transform(raw, id) {
164
- if (!isCSSRequest(id) || commonjsProxyRE.test(id)) {
165
- return
166
- }
167
-
168
- const urlReplacer: CssUrlReplacer = async (url, importer) => {
169
- if (checkPublicFile(url, config)) {
170
- return config.base + url.slice(1)
171
- }
172
- const resolved = await resolveUrl(url, importer)
173
- if (resolved) {
174
- return fileToUrl(resolved, config, this)
175
- }
176
- return url
177
- }
178
-
179
- const {
180
- code: css,
181
- modules,
182
- deps
183
- } = await compileCSS(
184
- id,
185
- raw,
186
- config,
187
- urlReplacer,
188
- atImportResolvers,
189
- server
190
- )
191
- if (modules) {
192
- moduleCache.set(id, modules)
193
- }
194
-
195
- // track deps for build watch mode
196
- if (config.command === 'build' && config.build.watch && deps) {
197
- for (const file of deps) {
198
- this.addWatchFile(file)
199
- }
200
- }
201
-
202
- // dev
203
- if (server) {
204
- // server only logic for handling CSS @import dependency hmr
205
- const { moduleGraph } = server
206
- const thisModule = moduleGraph.getModuleById(id)
207
- if (thisModule) {
208
- // CSS modules cannot self-accept since it exports values
209
- const isSelfAccepting = !modules
210
- if (deps) {
211
- // record deps in the module graph so edits to @import css can trigger
212
- // main import to hot update
213
- const depModules = new Set<string | ModuleNode>()
214
- for (const file of deps) {
215
- depModules.add(
216
- isCSSRequest(file)
217
- ? moduleGraph.createFileOnlyEntry(file)
218
- : await moduleGraph.ensureEntryFromUrl(
219
- (
220
- await fileToUrl(file, config, this)
221
- ).replace(config.base, '/')
222
- )
223
- )
224
- }
225
- moduleGraph.updateModuleInfo(
226
- thisModule,
227
- depModules,
228
- // The root CSS proxy module is self-accepting and should not
229
- // have an explicit accept list
230
- new Set(),
231
- isSelfAccepting
232
- )
233
- for (const file of deps) {
234
- this.addWatchFile(file)
235
- }
236
- } else {
237
- thisModule.isSelfAccepting = isSelfAccepting
238
- }
239
- }
240
- }
241
-
242
- return {
243
- code: css,
244
- // TODO CSS source map
245
- map: { mappings: '' }
246
- }
247
- }
248
- }
249
- }
250
-
251
- /**
252
- * Plugin applied after user plugins
253
- */
254
- export function cssPostPlugin(config: ResolvedConfig): Plugin {
255
- // styles initialization in buildStart causes a styling loss in watch
256
- const styles: Map<string, string> = new Map<string, string>()
257
- let pureCssChunks: Set<string>
258
-
259
- // when there are multiple rollup outputs and extracting CSS, only emit once,
260
- // since output formats have no effect on the generated CSS.
261
- let outputToExtractedCSSMap: Map<NormalizedOutputOptions, string>
262
- let hasEmitted = false
263
-
264
- return {
265
- name: 'vite:css-post',
266
-
267
- buildStart() {
268
- // Ensure new caches for every build (i.e. rebuilding in watch mode)
269
- pureCssChunks = new Set<string>()
270
- outputToExtractedCSSMap = new Map<NormalizedOutputOptions, string>()
271
- hasEmitted = false
272
- },
273
-
274
- async transform(css, id, ssr) {
275
- if (!isCSSRequest(id) || commonjsProxyRE.test(id)) {
276
- return
277
- }
278
-
279
- const inlined = inlineRE.test(id)
280
- const modules = cssModulesCache.get(config)!.get(id)
281
- const modulesCode =
282
- modules && dataToEsm(modules, { namedExports: true, preferConst: true })
283
-
284
- if (config.command === 'serve') {
285
- if (isDirectCSSRequest(id)) {
286
- return css
287
- } else {
288
- // server only
289
- if (ssr) {
290
- return modulesCode || `export default ${JSON.stringify(css)}`
291
- }
292
- if (inlined) {
293
- return `export default ${JSON.stringify(css)}`
294
- }
295
- return [
296
- `import { updateStyle, removeStyle } from ${JSON.stringify(
297
- path.posix.join(config.base, CLIENT_PUBLIC_PATH)
298
- )}`,
299
- `const id = ${JSON.stringify(id)}`,
300
- `const css = ${JSON.stringify(css)}`,
301
- `updateStyle(id, css)`,
302
- // css modules exports change on edit so it can't self accept
303
- `${modulesCode || `import.meta.hot.accept()\nexport default css`}`,
304
- `import.meta.hot.prune(() => removeStyle(id))`
305
- ].join('\n')
306
- }
307
- }
308
-
309
- // build CSS handling ----------------------------------------------------
310
-
311
- // record css
312
- if (!inlined) {
313
- styles.set(id, css)
314
- } else {
315
- css = await minifyCSS(css, config)
316
- }
317
-
318
- return {
319
- code:
320
- modulesCode ||
321
- (usedRE.test(id)
322
- ? `export default ${JSON.stringify(css)}`
323
- : `export default ''`),
324
- map: { mappings: '' },
325
- // avoid the css module from being tree-shaken so that we can retrieve
326
- // it in renderChunk()
327
- moduleSideEffects: inlined ? false : 'no-treeshake'
328
- }
329
- },
330
-
331
- async renderChunk(code, chunk, opts) {
332
- let chunkCSS = ''
333
- let isPureCssChunk = true
334
- const ids = Object.keys(chunk.modules)
335
- for (const id of ids) {
336
- if (
337
- !isCSSRequest(id) ||
338
- cssModuleRE.test(id) ||
339
- commonjsProxyRE.test(id)
340
- ) {
341
- isPureCssChunk = false
342
- }
343
- if (styles.has(id)) {
344
- chunkCSS += styles.get(id)
345
- }
346
- }
347
-
348
- if (!chunkCSS) {
349
- return null
350
- }
351
-
352
- // resolve asset URL placeholders to their built file URLs and perform
353
- // minification if necessary
354
- const processChunkCSS = async (
355
- css: string,
356
- {
357
- inlined,
358
- minify
359
- }: {
360
- inlined: boolean
361
- minify: boolean
362
- }
363
- ) => {
364
- // replace asset url references with resolved url.
365
- const isRelativeBase = config.base === '' || config.base.startsWith('.')
366
- css = css.replace(assetUrlRE, (_, fileHash, postfix = '') => {
367
- const filename = getAssetFilename(fileHash, config) + postfix
368
- registerAssetToChunk(chunk, filename)
369
- if (!isRelativeBase || inlined) {
370
- // absolute base or relative base but inlined (injected as style tag into
371
- // index.html) use the base as-is
372
- return config.base + filename
373
- } else {
374
- // relative base + extracted CSS - asset file will be in the same dir
375
- return `./${path.posix.basename(filename)}`
376
- }
377
- })
378
- // only external @imports should exist at this point - and they need to
379
- // be hoisted to the top of the CSS chunk per spec (#1845)
380
- if (css.includes('@import')) {
381
- css = await hoistAtImports(css)
382
- }
383
- if (minify && config.build.minify) {
384
- css = await minifyCSS(css, config)
385
- }
386
- return css
387
- }
388
-
389
- if (config.build.cssCodeSplit) {
390
- if (isPureCssChunk) {
391
- // this is a shared CSS-only chunk that is empty.
392
- pureCssChunks.add(chunk.fileName)
393
- }
394
- if (opts.format === 'es' || opts.format === 'cjs') {
395
- chunkCSS = await processChunkCSS(chunkCSS, {
396
- inlined: false,
397
- minify: true
398
- })
399
- // emit corresponding css file
400
- const fileHandle = this.emitFile({
401
- name: chunk.name + '.css',
402
- type: 'asset',
403
- source: chunkCSS
404
- })
405
- chunkToEmittedCssFileMap.set(
406
- chunk,
407
- new Set([this.getFileName(fileHandle)])
408
- )
409
- } else if (!config.build.ssr) {
410
- // legacy build, inline css
411
- chunkCSS = await processChunkCSS(chunkCSS, {
412
- inlined: true,
413
- minify: true
414
- })
415
- const style = `__vite_style__`
416
- const injectCode =
417
- `var ${style} = document.createElement('style');` +
418
- `${style}.innerHTML = ${JSON.stringify(chunkCSS)};` +
419
- `document.head.appendChild(${style});`
420
- if (config.build.sourcemap) {
421
- const s = new MagicString(code)
422
- s.prepend(injectCode)
423
- return {
424
- code: s.toString(),
425
- map: s.generateMap({ hires: true })
426
- }
427
- } else {
428
- return { code: injectCode + code }
429
- }
430
- }
431
- } else {
432
- // non-split extracted CSS will be minified together
433
- chunkCSS = await processChunkCSS(chunkCSS, {
434
- inlined: false,
435
- minify: false
436
- })
437
- outputToExtractedCSSMap.set(
438
- opts,
439
- (outputToExtractedCSSMap.get(opts) || '') + chunkCSS
440
- )
441
- }
442
- return null
443
- },
444
-
445
- async generateBundle(opts, bundle) {
446
- // remove empty css chunks and their imports
447
- if (pureCssChunks.size) {
448
- const emptyChunkFiles = [...pureCssChunks]
449
- .map((file) => path.basename(file))
450
- .join('|')
451
- .replace(/\./g, '\\.')
452
- const emptyChunkRE = new RegExp(
453
- opts.format === 'es'
454
- ? `\\bimport\\s*"[^"]*(?:${emptyChunkFiles})";\n?`
455
- : `\\brequire\\(\\s*"[^"]*(?:${emptyChunkFiles})"\\);\n?`,
456
- 'g'
457
- )
458
- for (const file in bundle) {
459
- const chunk = bundle[file]
460
- if (chunk.type === 'chunk') {
461
- // remove pure css chunk from other chunk's imports,
462
- // and also register the emitted CSS files under the importer
463
- // chunks instead.
464
- chunk.imports = chunk.imports.filter((file) => {
465
- if (pureCssChunks.has(file)) {
466
- const css = chunkToEmittedCssFileMap.get(
467
- bundle[file] as OutputChunk
468
- )
469
- if (css) {
470
- let existing = chunkToEmittedCssFileMap.get(chunk)
471
- if (!existing) {
472
- existing = new Set()
473
- }
474
- css.forEach((file) => existing!.add(file))
475
- chunkToEmittedCssFileMap.set(chunk, existing)
476
- }
477
- return false
478
- }
479
- return true
480
- })
481
- chunk.code = chunk.code.replace(
482
- emptyChunkRE,
483
- // remove css import while preserving source map location
484
- (m) => `/* empty css ${''.padEnd(m.length - 15)}*/`
485
- )
486
- }
487
- }
488
- const removedPureCssFiles = removedPureCssFilesCache.get(config)!
489
- pureCssChunks.forEach((fileName) => {
490
- removedPureCssFiles.set(fileName, bundle[fileName] as RenderedChunk)
491
- delete bundle[fileName]
492
- })
493
- }
494
-
495
- let extractedCss = outputToExtractedCSSMap.get(opts)
496
- if (extractedCss && !hasEmitted) {
497
- hasEmitted = true
498
- // minify css
499
- if (config.build.minify) {
500
- extractedCss = await minifyCSS(extractedCss, config)
501
- }
502
- this.emitFile({
503
- name: 'style.css',
504
- type: 'asset',
505
- source: extractedCss
506
- })
507
- }
508
- }
509
- }
510
- }
511
-
512
- interface CSSAtImportResolvers {
513
- css: ResolveFn
514
- sass: ResolveFn
515
- less: ResolveFn
516
- }
517
-
518
- function createCSSResolvers(config: ResolvedConfig): CSSAtImportResolvers {
519
- let cssResolve: ResolveFn | undefined
520
- let sassResolve: ResolveFn | undefined
521
- let lessResolve: ResolveFn | undefined
522
- return {
523
- get css() {
524
- return (
525
- cssResolve ||
526
- (cssResolve = config.createResolver({
527
- extensions: ['.css'],
528
- mainFields: ['style'],
529
- tryIndex: false,
530
- preferRelative: true
531
- }))
532
- )
533
- },
534
-
535
- get sass() {
536
- return (
537
- sassResolve ||
538
- (sassResolve = config.createResolver({
539
- extensions: ['.scss', '.sass', '.css'],
540
- mainFields: ['sass', 'style'],
541
- tryIndex: true,
542
- tryPrefix: '_',
543
- preferRelative: true
544
- }))
545
- )
546
- },
547
-
548
- get less() {
549
- return (
550
- lessResolve ||
551
- (lessResolve = config.createResolver({
552
- extensions: ['.less', '.css'],
553
- mainFields: ['less', 'style'],
554
- tryIndex: false,
555
- preferRelative: true
556
- }))
557
- )
558
- }
559
- }
560
- }
561
-
562
- function getCssResolversKeys(
563
- resolvers: CSSAtImportResolvers
564
- ): Array<keyof CSSAtImportResolvers> {
565
- return Object.keys(resolvers) as unknown as Array<keyof CSSAtImportResolvers>
566
- }
567
-
568
- async function compileCSS(
569
- id: string,
570
- code: string,
571
- config: ResolvedConfig,
572
- urlReplacer: CssUrlReplacer,
573
- atImportResolvers: CSSAtImportResolvers,
574
- server?: ViteDevServer
575
- ): Promise<{
576
- code: string
577
- map?: SourceMap
578
- ast?: Postcss.Result
579
- modules?: Record<string, string>
580
- deps?: Set<string>
581
- }> {
582
- const { modules: modulesOptions, preprocessorOptions } = config.css || {}
583
- const isModule = modulesOptions !== false && cssModuleRE.test(id)
584
- // although at serve time it can work without processing, we do need to
585
- // crawl them in order to register watch dependencies.
586
- const needInlineImport = code.includes('@import')
587
- const hasUrl = cssUrlRE.test(code) || cssImageSetRE.test(code)
588
- const postcssConfig = await resolvePostcssConfig(config)
589
- const lang = id.match(cssLangRE)?.[1] as CssLang | undefined
590
-
591
- // 1. plain css that needs no processing
592
- if (
593
- lang === 'css' &&
594
- !postcssConfig &&
595
- !isModule &&
596
- !needInlineImport &&
597
- !hasUrl
598
- ) {
599
- return { code }
600
- }
601
-
602
- let map: SourceMap | undefined
603
- let modules: Record<string, string> | undefined
604
- const deps = new Set<string>()
605
-
606
- // 2. pre-processors: sass etc.
607
- if (isPreProcessor(lang)) {
608
- const preProcessor = preProcessors[lang]
609
- let opts = (preprocessorOptions && preprocessorOptions[lang]) || {}
610
- // support @import from node dependencies by default
611
- switch (lang) {
612
- case PreprocessLang.scss:
613
- case PreprocessLang.sass:
614
- opts = {
615
- includePaths: ['node_modules'],
616
- alias: config.resolve.alias,
617
- ...opts
618
- }
619
- break
620
- case PreprocessLang.less:
621
- case PreprocessLang.styl:
622
- case PreprocessLang.stylus:
623
- opts = {
624
- paths: ['node_modules'],
625
- alias: config.resolve.alias,
626
- ...opts
627
- }
628
- }
629
- // important: set this for relative import resolving
630
- opts.filename = cleanUrl(id)
631
- const preprocessResult = await preProcessor(
632
- code,
633
- config.root,
634
- opts,
635
- atImportResolvers
636
- )
637
- if (preprocessResult.errors.length) {
638
- throw preprocessResult.errors[0]
639
- }
640
-
641
- code = preprocessResult.code
642
- map = preprocessResult.map as SourceMap
643
- if (preprocessResult.deps) {
644
- preprocessResult.deps.forEach((dep) => {
645
- // sometimes sass registers the file itself as a dep
646
- if (normalizePath(dep) !== normalizePath(opts.filename)) {
647
- deps.add(dep)
648
- }
649
- })
650
- }
651
- }
652
-
653
- // 3. postcss
654
- const postcssOptions = (postcssConfig && postcssConfig.options) || {}
655
- const postcssPlugins =
656
- postcssConfig && postcssConfig.plugins ? postcssConfig.plugins.slice() : []
657
-
658
- if (needInlineImport) {
659
- postcssPlugins.unshift(
660
- (await import('postcss-import')).default({
661
- async resolve(id, basedir) {
662
- const resolved = await atImportResolvers.css(
663
- id,
664
- path.join(basedir, '*')
665
- )
666
- if (resolved) {
667
- return path.resolve(resolved)
668
- }
669
- return id
670
- }
671
- })
672
- )
673
- }
674
- postcssPlugins.push(
675
- UrlRewritePostcssPlugin({
676
- replacer: urlReplacer
677
- }) as Postcss.Plugin
678
- )
679
-
680
- if (isModule) {
681
- postcssPlugins.unshift(
682
- (await import('postcss-modules')).default({
683
- ...modulesOptions,
684
- getJSON(
685
- cssFileName: string,
686
- _modules: Record<string, string>,
687
- outputFileName: string
688
- ) {
689
- modules = _modules
690
- if (modulesOptions && typeof modulesOptions.getJSON === 'function') {
691
- modulesOptions.getJSON(cssFileName, _modules, outputFileName)
692
- }
693
- },
694
- async resolve(id: string) {
695
- for (const key of getCssResolversKeys(atImportResolvers)) {
696
- const resolved = await atImportResolvers[key](id)
697
- if (resolved) {
698
- return path.resolve(resolved)
699
- }
700
- }
701
-
702
- return id
703
- }
704
- })
705
- )
706
- }
707
-
708
- if (!postcssPlugins.length) {
709
- return {
710
- code,
711
- map
712
- }
713
- }
714
-
715
- // postcss is an unbundled dep and should be lazy imported
716
- const postcssResult = await (await import('postcss'))
717
- .default(postcssPlugins)
718
- .process(code, {
719
- ...postcssOptions,
720
- to: id,
721
- from: id,
722
- map: {
723
- inline: false,
724
- annotation: false,
725
- prev: map
726
- }
727
- })
728
-
729
- // record CSS dependencies from @imports
730
- for (const message of postcssResult.messages) {
731
- if (message.type === 'dependency') {
732
- deps.add(message.file as string)
733
- } else if (message.type === 'dir-dependency') {
734
- // https://github.com/postcss/postcss/blob/main/docs/guidelines/plugin.md#3-dependencies
735
- const { dir, glob: globPattern = '**' } = message
736
- const pattern =
737
- normalizePath(path.resolve(path.dirname(id), dir)) + `/` + globPattern
738
- const files = glob.sync(pattern, {
739
- ignore: ['**/node_modules/**']
740
- })
741
- for (let i = 0; i < files.length; i++) {
742
- deps.add(files[i])
743
- }
744
- if (server) {
745
- // register glob importers so we can trigger updates on file add/remove
746
- if (!(id in server._globImporters)) {
747
- server._globImporters[id] = {
748
- module: server.moduleGraph.getModuleById(id)!,
749
- importGlobs: []
750
- }
751
- }
752
- server._globImporters[id].importGlobs.push({
753
- base: config.root,
754
- pattern
755
- })
756
- }
757
- } else if (message.type === 'warning') {
758
- let msg = `[vite:css] ${message.text}`
759
- if (message.line && message.column) {
760
- msg += `\n${generateCodeFrame(code, {
761
- line: message.line,
762
- column: message.column
763
- })}`
764
- }
765
- config.logger.warn(chalk.yellow(msg))
766
- }
767
- }
768
-
769
- return {
770
- ast: postcssResult,
771
- code: postcssResult.css,
772
- map: postcssResult.map as any,
773
- modules,
774
- deps
775
- }
776
- }
777
-
778
- interface PostCSSConfigResult {
779
- options: Postcss.ProcessOptions
780
- plugins: Postcss.Plugin[]
781
- }
782
-
783
- async function resolvePostcssConfig(
784
- config: ResolvedConfig
785
- ): Promise<PostCSSConfigResult | null> {
786
- let result = postcssConfigCache.get(config)
787
- if (result !== undefined) {
788
- return result
789
- }
790
-
791
- // inline postcss config via vite config
792
- const inlineOptions = config.css?.postcss
793
- if (isObject(inlineOptions)) {
794
- const options = { ...inlineOptions }
795
-
796
- delete options.plugins
797
- result = {
798
- options,
799
- plugins: inlineOptions.plugins || []
800
- }
801
- } else {
802
- try {
803
- const searchPath =
804
- typeof inlineOptions === 'string' ? inlineOptions : config.root
805
- // @ts-ignore
806
- result = await postcssrc({}, searchPath)
807
- } catch (e) {
808
- if (!/No PostCSS Config found/.test(e.message)) {
809
- throw e
810
- }
811
- result = null
812
- }
813
- }
814
-
815
- postcssConfigCache.set(config, result)
816
- return result
817
- }
818
-
819
- type CssUrlReplacer = (
820
- url: string,
821
- importer?: string
822
- ) => string | Promise<string>
823
- // https://drafts.csswg.org/css-syntax-3/#identifier-code-point
824
- export const cssUrlRE =
825
- /(?<=^|[^\w\-\u0080-\uffff])url\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/
826
- const cssImageSetRE = /image-set\(([^)]+)\)/
827
-
828
- const UrlRewritePostcssPlugin: Postcss.PluginCreator<{
829
- replacer: CssUrlReplacer
830
- }> = (opts) => {
831
- if (!opts) {
832
- throw new Error('base or replace is required')
833
- }
834
-
835
- return {
836
- postcssPlugin: 'vite-url-rewrite',
837
- Once(root) {
838
- const promises: Promise<void>[] = []
839
- root.walkDecls((declaration) => {
840
- const isCssUrl = cssUrlRE.test(declaration.value)
841
- const isCssImageSet = cssImageSetRE.test(declaration.value)
842
- if (isCssUrl || isCssImageSet) {
843
- const replacerForDeclaration = (rawUrl: string) => {
844
- const importer = declaration.source?.input.file
845
- return opts.replacer(rawUrl, importer)
846
- }
847
- const rewriterToUse = isCssUrl ? rewriteCssUrls : rewriteCssImageSet
848
- promises.push(
849
- rewriterToUse(declaration.value, replacerForDeclaration).then(
850
- (url) => {
851
- declaration.value = url
852
- }
853
- )
854
- )
855
- }
856
- })
857
- if (promises.length) {
858
- return Promise.all(promises) as any
859
- }
860
- }
861
- }
862
- }
863
- UrlRewritePostcssPlugin.postcss = true
864
-
865
- function rewriteCssUrls(
866
- css: string,
867
- replacer: CssUrlReplacer
868
- ): Promise<string> {
869
- return asyncReplace(css, cssUrlRE, async (match) => {
870
- const [matched, rawUrl] = match
871
- return await doUrlReplace(rawUrl, matched, replacer)
872
- })
873
- }
874
-
875
- function rewriteCssImageSet(
876
- css: string,
877
- replacer: CssUrlReplacer
878
- ): Promise<string> {
879
- return asyncReplace(css, cssImageSetRE, async (match) => {
880
- const [matched, rawUrl] = match
881
- const url = await processSrcSet(rawUrl, ({ url }) =>
882
- doUrlReplace(url, matched, replacer)
883
- )
884
- return `image-set(${url})`
885
- })
886
- }
887
- async function doUrlReplace(
888
- rawUrl: string,
889
- matched: string,
890
- replacer: CssUrlReplacer
891
- ) {
892
- let wrap = ''
893
- const first = rawUrl[0]
894
- if (first === `"` || first === `'`) {
895
- wrap = first
896
- rawUrl = rawUrl.slice(1, -1)
897
- }
898
- if (isExternalUrl(rawUrl) || isDataUrl(rawUrl) || rawUrl.startsWith('#')) {
899
- return matched
900
- }
901
-
902
- return `url(${wrap}${await replacer(rawUrl)}${wrap})`
903
- }
904
-
905
- async function minifyCSS(css: string, config: ResolvedConfig) {
906
- const { code, warnings } = await transform(css, {
907
- loader: 'css',
908
- minify: true,
909
- target: config.build.target || undefined
910
- })
911
- if (warnings.length) {
912
- const msgs = await formatMessages(warnings, { kind: 'warning' })
913
- config.logger.warn(
914
- chalk.yellow(`warnings when minifying css:\n${msgs.join('\n')}`)
915
- )
916
- }
917
- return code
918
- }
919
-
920
- // #1845
921
- // CSS @import can only appear at top of the file. We need to hoist all @import
922
- // to top when multiple files are concatenated.
923
- async function hoistAtImports(css: string) {
924
- const postcss = await import('postcss')
925
- return (await postcss.default([AtImportHoistPlugin]).process(css)).css
926
- }
927
-
928
- const AtImportHoistPlugin: Postcss.PluginCreator<any> = () => {
929
- return {
930
- postcssPlugin: 'vite-hoist-at-imports',
931
- Once(root) {
932
- const imports: Postcss.AtRule[] = []
933
- root.walkAtRules((rule) => {
934
- if (rule.name === 'import') {
935
- // record in reverse so that can simply prepend to preserve order
936
- imports.unshift(rule)
937
- }
938
- })
939
- imports.forEach((i) => root.prepend(i))
940
- }
941
- }
942
- }
943
- AtImportHoistPlugin.postcss = true
944
-
945
- // Preprocessor support. This logic is largely replicated from @vue/compiler-sfc
946
-
947
- type PreprocessorAdditionalData =
948
- | string
949
- | ((source: string, filename: string) => string | Promise<string>)
950
-
951
- type StylePreprocessorOptions = {
952
- [key: string]: any
953
- additionalData?: PreprocessorAdditionalData
954
- filename: string
955
- alias: Alias[]
956
- }
957
-
958
- type SassStylePreprocessorOptions = StylePreprocessorOptions & Sass.Options
959
-
960
- type StylePreprocessor = (
961
- source: string,
962
- root: string,
963
- options: StylePreprocessorOptions,
964
- resolvers: CSSAtImportResolvers
965
- ) => StylePreprocessorResults | Promise<StylePreprocessorResults>
966
-
967
- type SassStylePreprocessor = (
968
- source: string,
969
- root: string,
970
- options: SassStylePreprocessorOptions,
971
- resolvers: CSSAtImportResolvers
972
- ) => StylePreprocessorResults | Promise<StylePreprocessorResults>
973
-
974
- export interface StylePreprocessorResults {
975
- code: string
976
- map?: object
977
- errors: RollupError[]
978
- deps: string[]
979
- }
980
-
981
- const loadedPreprocessors: Partial<Record<PreprocessLang, any>> = {}
982
-
983
- function loadPreprocessor(lang: PreprocessLang.scss, root: string): typeof Sass
984
- function loadPreprocessor(lang: PreprocessLang.sass, root: string): typeof Sass
985
- function loadPreprocessor(lang: PreprocessLang.less, root: string): typeof Less
986
- function loadPreprocessor(
987
- lang: PreprocessLang.stylus,
988
- root: string
989
- ): typeof Stylus
990
- function loadPreprocessor(lang: PreprocessLang, root: string): any {
991
- if (lang in loadedPreprocessors) {
992
- return loadedPreprocessors[lang]
993
- }
994
- try {
995
- // Search for the preprocessor in the root directory first, and fall back
996
- // to the default require paths.
997
- const fallbackPaths = require.resolve.paths?.(lang) || []
998
- const resolved = require.resolve(lang, { paths: [root, ...fallbackPaths] })
999
- return (loadedPreprocessors[lang] = require(resolved))
1000
- } catch (e) {
1001
- throw new Error(
1002
- `Preprocessor dependency "${lang}" not found. Did you install it?`
1003
- )
1004
- }
1005
- }
1006
-
1007
- // .scss/.sass processor
1008
- const scss: SassStylePreprocessor = async (
1009
- source,
1010
- root,
1011
- options,
1012
- resolvers
1013
- ) => {
1014
- const render = loadPreprocessor(PreprocessLang.sass, root).render
1015
- const internalImporter: Sass.Importer = (url, importer, done) => {
1016
- resolvers.sass(url, importer).then((resolved) => {
1017
- if (resolved) {
1018
- rebaseUrls(resolved, options.filename, options.alias)
1019
- .then(done)
1020
- .catch(done)
1021
- } else {
1022
- done(null)
1023
- }
1024
- })
1025
- }
1026
- const importer = [internalImporter]
1027
- if (options.importer) {
1028
- Array.isArray(options.importer)
1029
- ? importer.push(...options.importer)
1030
- : importer.push(options.importer)
1031
- }
1032
-
1033
- const finalOptions: Sass.Options = {
1034
- ...options,
1035
- data: await getSource(source, options.filename, options.additionalData),
1036
- file: options.filename,
1037
- outFile: options.filename,
1038
- importer
1039
- }
1040
-
1041
- try {
1042
- const result = await new Promise<Sass.Result>((resolve, reject) => {
1043
- render(finalOptions, (err, res) => {
1044
- if (err) {
1045
- reject(err)
1046
- } else {
1047
- resolve(res)
1048
- }
1049
- })
1050
- })
1051
- const deps = result.stats.includedFiles
1052
-
1053
- return {
1054
- code: result.css.toString(),
1055
- errors: [],
1056
- deps
1057
- }
1058
- } catch (e) {
1059
- // normalize SASS error
1060
- e.id = e.file
1061
- e.frame = e.formatted
1062
- return { code: '', errors: [e], deps: [] }
1063
- }
1064
- }
1065
-
1066
- const sass: SassStylePreprocessor = (source, root, options, aliasResolver) =>
1067
- scss(
1068
- source,
1069
- root,
1070
- {
1071
- ...options,
1072
- indentedSyntax: true
1073
- },
1074
- aliasResolver
1075
- )
1076
-
1077
- /**
1078
- * relative url() inside \@imported sass and less files must be rebased to use
1079
- * root file as base.
1080
- */
1081
- async function rebaseUrls(
1082
- file: string,
1083
- rootFile: string,
1084
- alias: Alias[]
1085
- ): Promise<Sass.ImporterReturnType> {
1086
- file = path.resolve(file) // ensure os-specific flashes
1087
- // in the same dir, no need to rebase
1088
- const fileDir = path.dirname(file)
1089
- const rootDir = path.dirname(rootFile)
1090
- if (fileDir === rootDir) {
1091
- return { file }
1092
- }
1093
- // no url()
1094
- const content = fs.readFileSync(file, 'utf-8')
1095
- if (!cssUrlRE.test(content)) {
1096
- return { file }
1097
- }
1098
- const rebased = await rewriteCssUrls(content, (url) => {
1099
- if (url.startsWith('/')) return url
1100
- // match alias, no need to rewrite
1101
- for (const { find } of alias) {
1102
- const matches =
1103
- typeof find === 'string' ? url.startsWith(find) : find.test(url)
1104
- if (matches) {
1105
- return url
1106
- }
1107
- }
1108
- const absolute = path.resolve(fileDir, url)
1109
- const relative = path.relative(rootDir, absolute)
1110
- return normalizePath(relative)
1111
- })
1112
- return {
1113
- file,
1114
- contents: rebased
1115
- }
1116
- }
1117
-
1118
- // .less
1119
- const less: StylePreprocessor = async (source, root, options, resolvers) => {
1120
- const nodeLess = loadPreprocessor(PreprocessLang.less, root)
1121
- const viteResolverPlugin = createViteLessPlugin(
1122
- nodeLess,
1123
- options.filename,
1124
- options.alias,
1125
- resolvers
1126
- )
1127
- source = await getSource(source, options.filename, options.additionalData)
1128
-
1129
- let result: Less.RenderOutput | undefined
1130
- try {
1131
- result = await nodeLess.render(source, {
1132
- ...options,
1133
- plugins: [viteResolverPlugin, ...(options.plugins || [])]
1134
- })
1135
- } catch (e) {
1136
- const error = e as Less.RenderError
1137
- // normalize error info
1138
- const normalizedError: RollupError = new Error(error.message || error.type)
1139
- normalizedError.loc = {
1140
- file: error.filename || options.filename,
1141
- line: error.line,
1142
- column: error.column
1143
- }
1144
- return { code: '', errors: [normalizedError], deps: [] }
1145
- }
1146
- return {
1147
- code: result.css.toString(),
1148
- deps: result.imports,
1149
- errors: []
1150
- }
1151
- }
1152
-
1153
- /**
1154
- * Less manager, lazy initialized
1155
- */
1156
- let ViteLessManager: any
1157
-
1158
- function createViteLessPlugin(
1159
- less: typeof Less,
1160
- rootFile: string,
1161
- alias: Alias[],
1162
- resolvers: CSSAtImportResolvers
1163
- ): Less.Plugin {
1164
- if (!ViteLessManager) {
1165
- ViteLessManager = class ViteManager extends less.FileManager {
1166
- resolvers
1167
- rootFile
1168
- alias
1169
- constructor(
1170
- rootFile: string,
1171
- resolvers: CSSAtImportResolvers,
1172
- alias: Alias[]
1173
- ) {
1174
- super()
1175
- this.rootFile = rootFile
1176
- this.resolvers = resolvers
1177
- this.alias = alias
1178
- }
1179
- override supports() {
1180
- return true
1181
- }
1182
- override supportsSync() {
1183
- return false
1184
- }
1185
- override async loadFile(
1186
- filename: string,
1187
- dir: string,
1188
- opts: any,
1189
- env: any
1190
- ): Promise<Less.FileLoadResult> {
1191
- const resolved = await this.resolvers.less(
1192
- filename,
1193
- path.join(dir, '*')
1194
- )
1195
- if (resolved) {
1196
- const result = await rebaseUrls(resolved, this.rootFile, this.alias)
1197
- let contents: string
1198
- if (result && 'contents' in result) {
1199
- contents = result.contents
1200
- } else {
1201
- contents = fs.readFileSync(resolved, 'utf-8')
1202
- }
1203
- return {
1204
- filename: path.resolve(resolved),
1205
- contents
1206
- }
1207
- } else {
1208
- return super.loadFile(filename, dir, opts, env)
1209
- }
1210
- }
1211
- }
1212
- }
1213
-
1214
- return {
1215
- install(_, pluginManager) {
1216
- pluginManager.addFileManager(
1217
- new ViteLessManager(rootFile, resolvers, alias)
1218
- )
1219
- },
1220
- minVersion: [3, 0, 0]
1221
- }
1222
- }
1223
-
1224
- // .styl
1225
- const styl: StylePreprocessor = async (source, root, options) => {
1226
- const nodeStylus = loadPreprocessor(PreprocessLang.stylus, root)
1227
- // Get source with preprocessor options.additionalData. Make sure a new line separator
1228
- // is added to avoid any render error, as added stylus content may not have semi-colon separators
1229
- source = await getSource(
1230
- source,
1231
- options.filename,
1232
- options.additionalData,
1233
- '\n'
1234
- )
1235
- // Get preprocessor options.imports dependencies as stylus
1236
- // does not return them with its builtin `.deps()` method
1237
- const importsDeps = (options.imports ?? []).map((dep: string) =>
1238
- path.resolve(dep)
1239
- )
1240
- try {
1241
- const ref = nodeStylus(source, options)
1242
-
1243
- // if (map) ref.set('sourcemap', { inline: false, comment: false })
1244
-
1245
- const result = ref.render()
1246
-
1247
- // Concat imports deps with computed deps
1248
- const deps = [...ref.deps(), ...importsDeps]
1249
-
1250
- return { code: result, errors: [], deps }
1251
- } catch (e) {
1252
- return { code: '', errors: [e], deps: [] }
1253
- }
1254
- }
1255
-
1256
- function getSource(
1257
- source: string,
1258
- filename: string,
1259
- additionalData?: PreprocessorAdditionalData,
1260
- sep: string = ''
1261
- ): string | Promise<string> {
1262
- if (!additionalData) return source
1263
- if (typeof additionalData === 'function') {
1264
- return additionalData(source, filename)
1265
- }
1266
- return additionalData + sep + source
1267
- }
1268
-
1269
- const preProcessors = Object.freeze({
1270
- [PreprocessLang.less]: less,
1271
- [PreprocessLang.sass]: sass,
1272
- [PreprocessLang.scss]: scss,
1273
- [PreprocessLang.styl]: styl,
1274
- [PreprocessLang.stylus]: styl
1275
- })
1276
-
1277
- function isPreProcessor(lang: any): lang is PreprocessLang {
1278
- return lang && lang in preProcessors
1279
- }