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.
- package/CHANGELOG.md +66 -0
- package/LICENSE.md +161 -3011
- package/bin/vite.js +2 -1
- package/dist/node/chunks/{dep-91aa74e8.js → dep-1e0a75a8.js} +58 -32
- package/dist/node/chunks/dep-1e0a75a8.js.map +1 -0
- package/dist/node/chunks/{dep-e36486f6.js → dep-ac1b4bf9.js} +1 -1
- package/dist/node/chunks/dep-ac1b4bf9.js.map +1 -0
- package/dist/node/chunks/{dep-c7e510f9.js → dep-ba6b30a0.js} +27538 -4953
- package/dist/node/chunks/dep-ba6b30a0.js.map +1 -0
- package/dist/node/chunks/{dep-11213a75.js → dep-c4cf6e92.js} +19 -6
- package/dist/node/chunks/dep-c4cf6e92.js.map +1 -0
- package/dist/node/chunks/{dep-eb6ef720.js → dep-d574094c.js} +18 -5
- package/dist/node/chunks/dep-d574094c.js.map +1 -0
- package/dist/node/chunks/{dep-0d2f9464.js → dep-e39b05d6.js} +18 -5
- package/dist/node/chunks/dep-e39b05d6.js.map +1 -0
- package/dist/node/cli.js +60 -23992
- package/dist/node/cli.js.map +1 -1
- package/dist/node/index.d.ts +26 -8
- package/dist/node/index.js +18 -15
- package/dist/node/index.js.map +1 -1
- package/dist/node/terser.js +102 -55
- package/package.json +28 -13
- package/types/package.json +3 -0
- package/api-extractor.json +0 -54
- package/dist/node/chunks/dep-0d2f9464.js.map +0 -1
- package/dist/node/chunks/dep-11213a75.js.map +0 -1
- package/dist/node/chunks/dep-91aa74e8.js.map +0 -1
- package/dist/node/chunks/dep-c7e510f9.js.map +0 -1
- package/dist/node/chunks/dep-e36486f6.js.map +0 -1
- package/dist/node/chunks/dep-eb6ef720.js.map +0 -1
- package/dist/node/terser.js.map +0 -1
- package/rollup.config.js +0 -389
- package/scripts/patchTypes.js +0 -70
- package/src/node/__tests__/asset.spec.ts +0 -156
- package/src/node/__tests__/build.spec.ts +0 -67
- package/src/node/__tests__/config.spec.ts +0 -166
- package/src/node/__tests__/packages/name/package.json +0 -3
- package/src/node/__tests__/packages/noname/package.json +0 -1
- package/src/node/__tests__/plugins/css.spec.ts +0 -116
- package/src/node/__tests__/scan.spec.ts +0 -118
- package/src/node/__tests__/utils.spec.ts +0 -40
- package/src/node/build.ts +0 -783
- package/src/node/cli.ts +0 -239
- package/src/node/config.ts +0 -1033
- package/src/node/constants.ts +0 -87
- package/src/node/importGlob.ts +0 -173
- package/src/node/index.ts +0 -88
- package/src/node/logger.ts +0 -167
- package/src/node/optimizer/esbuildDepPlugin.ts +0 -216
- package/src/node/optimizer/index.ts +0 -410
- package/src/node/optimizer/registerMissing.ts +0 -102
- package/src/node/optimizer/scan.ts +0 -457
- package/src/node/plugin.ts +0 -138
- package/src/node/plugins/asset.ts +0 -365
- package/src/node/plugins/assetImportMetaUrl.ts +0 -99
- package/src/node/plugins/clientInjections.ts +0 -72
- package/src/node/plugins/css.ts +0 -1279
- package/src/node/plugins/dataUri.ts +0 -64
- package/src/node/plugins/define.ts +0 -107
- package/src/node/plugins/esbuild.ts +0 -280
- package/src/node/plugins/html.ts +0 -673
- package/src/node/plugins/importAnalysis.ts +0 -614
- package/src/node/plugins/importAnalysisBuild.ts +0 -334
- package/src/node/plugins/index.ts +0 -69
- package/src/node/plugins/json.ts +0 -75
- package/src/node/plugins/loadFallback.ts +0 -19
- package/src/node/plugins/manifest.ts +0 -123
- package/src/node/plugins/modulePreloadPolyfill.ts +0 -100
- package/src/node/plugins/preAlias.ts +0 -22
- package/src/node/plugins/reporter.ts +0 -244
- package/src/node/plugins/resolve.ts +0 -925
- package/src/node/plugins/terser.ts +0 -40
- package/src/node/plugins/wasm.ts +0 -72
- package/src/node/plugins/worker.ts +0 -117
- package/src/node/preview.ts +0 -82
- package/src/node/server/__tests__/fixtures/none/nested/package.json +0 -3
- package/src/node/server/__tests__/fixtures/pnpm/nested/package.json +0 -3
- package/src/node/server/__tests__/fixtures/pnpm/package.json +0 -3
- package/src/node/server/__tests__/fixtures/pnpm/pnpm-workspace.yaml +0 -0
- package/src/node/server/__tests__/fixtures/yarn/nested/package.json +0 -3
- package/src/node/server/__tests__/fixtures/yarn/package.json +0 -6
- package/src/node/server/__tests__/search-root.spec.ts +0 -31
- package/src/node/server/hmr.ts +0 -489
- package/src/node/server/http.ts +0 -198
- package/src/node/server/index.ts +0 -705
- package/src/node/server/middlewares/base.ts +0 -52
- package/src/node/server/middlewares/error.ts +0 -98
- package/src/node/server/middlewares/indexHtml.ts +0 -170
- package/src/node/server/middlewares/proxy.ts +0 -124
- package/src/node/server/middlewares/spaFallback.ts +0 -32
- package/src/node/server/middlewares/static.ts +0 -153
- package/src/node/server/middlewares/time.ts +0 -18
- package/src/node/server/middlewares/transform.ts +0 -196
- package/src/node/server/moduleGraph.ts +0 -200
- package/src/node/server/openBrowser.ts +0 -101
- package/src/node/server/pluginContainer.ts +0 -546
- package/src/node/server/searchRoot.ts +0 -70
- package/src/node/server/send.ts +0 -54
- package/src/node/server/sourcemap.ts +0 -54
- package/src/node/server/transformRequest.ts +0 -168
- package/src/node/server/ws.ts +0 -131
- package/src/node/ssr/__tests__/ssrTransform.spec.ts +0 -309
- package/src/node/ssr/ssrExternal.ts +0 -161
- package/src/node/ssr/ssrManifestPlugin.ts +0 -53
- package/src/node/ssr/ssrModuleLoader.ts +0 -214
- package/src/node/ssr/ssrStacktrace.ts +0 -75
- package/src/node/ssr/ssrTransform.ts +0 -452
- package/src/node/tsconfig.json +0 -14
- package/src/node/utils.ts +0 -565
- package/tsconfig.base.json +0 -11
package/src/node/plugins/css.ts
DELETED
|
@@ -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
|
-
}
|