Skip to content
This repository was archived by the owner on Jan 18, 2022. It is now read-only.

Commit 53b0e40

Browse files
committed
wip: more efficient style handling for vite
1 parent 62e340f commit 53b0e40

File tree

5 files changed

+65
-36
lines changed

5 files changed

+65
-36
lines changed

src/handleHotUpdate.ts

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import fs from 'fs'
2+
import _debug from 'debug'
23
import { parse, SFCBlock } from '@vue/compiler-sfc'
34
import { getDescriptor, setDescriptor } from './utils/descriptorCache'
45

6+
const debug = _debug('vite:hmr')
7+
58
/**
69
* Vite-specific HMR handling
710
*/
@@ -33,8 +36,10 @@ export async function handleHotUpdate(file: string, modules: any[]) {
3336
const filteredModules = []
3437

3538
const reload = () => {
36-
console.log(`[vue:reload] ${file}`)
37-
return modules.filter((m) => /type=script/.test(m.id))
39+
debug(`[vue:reload] ${file}`)
40+
return modules.filter(
41+
(m) => !/type=/.test(m.id) || /type=script/.test(m.id)
42+
)
3843
}
3944

4045
if (
@@ -52,16 +57,6 @@ export async function handleHotUpdate(file: string, modules: any[]) {
5257
const prevStyles = prevDescriptor.styles || []
5358
const nextStyles = descriptor.styles || []
5459

55-
// css modules update causes a reload because the $style object is changed
56-
// and it may be used in JS. It also needs to trigger a vue-style-update
57-
// event so the client busts the sw cache.
58-
if (
59-
prevStyles.some((s) => s.module != null) ||
60-
nextStyles.some((s) => s.module != null)
61-
) {
62-
return reload()
63-
}
64-
6560
// force reload if CSS vars injection changed
6661
if (descriptor.cssVars) {
6762
if (prevDescriptor.cssVars.join('') !== descriptor.cssVars.join('')) {
@@ -76,12 +71,21 @@ export async function handleHotUpdate(file: string, modules: any[]) {
7671

7772
// only need to update styles if not reloading, since reload forces
7873
// style updates as well.
79-
nextStyles.forEach((_, i) => {
80-
if (!prevStyles[i] || !isEqualBlock(prevStyles[i], nextStyles[i])) {
74+
for (let i = 0; i < nextStyles.length; i++) {
75+
const prev = prevStyles[i]
76+
const next = nextStyles[i]
77+
if (!prev || !isEqualBlock(prev, next)) {
78+
// css modules update causes a reload because the $style object is changed
79+
// and it may be used in JS.
80+
// if (prev.module != null || next.module != null) {
81+
// return modules.filter(
82+
// (m) => !/type=/.test(m.id) || /type=script/.test(m.id)
83+
// )
84+
// }
8185
didUpdateStyle = true
8286
filteredModules.push(modules.find((m) => m.id.includes(`index=${i}`)))
8387
}
84-
})
88+
}
8589

8690
const prevCustoms = prevDescriptor.customBlocks || []
8791
const nextCustoms = descriptor.customBlocks || []
@@ -108,7 +112,7 @@ export async function handleHotUpdate(file: string, modules: any[]) {
108112
updateType.push(`style`)
109113
}
110114
if (updateType.length) {
111-
console.log(`[vue:update(${updateType.join('&')})] ${file}`)
115+
debug(`[vue:update(${updateType.join('&')})] ${file}`)
112116
}
113117
return filteredModules
114118
}

src/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ export interface Options {
3131
include: string | RegExp | (string | RegExp)[]
3232
exclude: string | RegExp | (string | RegExp)[]
3333
target: 'node' | 'browser'
34+
vite: boolean
3435
hmr: boolean
3536
exposeFilename: boolean
36-
3737
customBlocks?: string[]
3838

3939
// if true, handle preprocessors directly instead of delegating to other
@@ -60,6 +60,7 @@ export interface Options {
6060
const defaultOptions: Options = {
6161
include: /\.vue$/,
6262
exclude: [],
63+
vite: false,
6364
hmr: false,
6465
target: 'browser',
6566
exposeFilename: false,
@@ -72,6 +73,10 @@ export default function PluginVue(userOptions: Partial<Options> = {}): Plugin {
7273
...userOptions,
7374
}
7475

76+
if (options.vite) {
77+
options.preprocessStyles = false
78+
}
79+
7580
const isServer = options.target === 'node'
7681
const isProduction =
7782
process.env.NODE_ENV === 'production' || process.env.BUILD === 'production'

src/sfc.ts

+24-9
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ export function transformSFCEntry(
6666
options,
6767
pluginContext
6868
)
69-
const stylesCode = genStyleCode(descriptor, scopeId, options.preprocessStyles)
69+
const stylesCode = genStyleCode(
70+
descriptor,
71+
scopeId,
72+
options.preprocessStyles,
73+
options.vite
74+
)
7075
const customBlocksCode = getCustomBlock(descriptor, filterCustomBlock)
7176
const output = [
7277
scriptImport,
@@ -158,7 +163,8 @@ function genScriptCode(
158163
function genStyleCode(
159164
descriptor: SFCDescriptor,
160165
scopeId: string,
161-
preprocessStyles?: boolean
166+
preprocessStyles?: boolean,
167+
isVite?: boolean
162168
) {
163169
let stylesCode = ``
164170
let hasCSSModules = false
@@ -188,7 +194,8 @@ function genStyleCode(
188194
i,
189195
styleRequest,
190196
styleRequestWithoutModule,
191-
style.module
197+
style.module,
198+
isVite
192199
)
193200
} else {
194201
stylesCode += `\nimport ${JSON.stringify(styleRequest)}`
@@ -224,14 +231,22 @@ function genCSSModulesCode(
224231
index: number,
225232
request: string,
226233
requestWithoutModule: string,
227-
moduleName: string | boolean
234+
moduleName: string | boolean,
235+
isVite?: boolean
228236
): string {
229237
const styleVar = `style${index}`
230-
let code =
231-
// first import the CSS for extraction
232-
`\nimport ${JSON.stringify(requestWithoutModule)}` +
233-
// then import the json file to expose to component...
234-
`\nimport ${styleVar} from ${JSON.stringify(request + '.js')}`
238+
let code
239+
if (!isVite) {
240+
code =
241+
// first import the CSS for extraction
242+
`\nimport ${JSON.stringify(requestWithoutModule)}` +
243+
// then import the json file to expose to component...
244+
`\nimport ${styleVar} from ${JSON.stringify(request + '.js')}`
245+
} else {
246+
// vite handles module.ext in a single import
247+
request = request.replace(/\.(\w+)$/, '.module.$1.js')
248+
code = `\n import ${styleVar} from ${JSON.stringify(request)}`
249+
}
235250

236251
// inject variable
237252
const name = typeof moduleName === 'string' ? moduleName : '$style'

src/style.ts

+15-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export async function transformStyle(
2020
const block = descriptor.styles[query.index]!
2121

2222
let preprocessOptions = options.preprocessOptions || {}
23-
const preprocessLang = (options.preprocessStyles
23+
const preprocessLang = (options.preprocessStyles && !options.vite
2424
? block.lang
2525
: undefined) as SFCAsyncStyleCompileOptions['preprocessLang']
2626

@@ -52,7 +52,8 @@ export async function transformStyle(
5252
isProd: isProduction,
5353
source: code,
5454
scoped: block.scoped,
55-
modules: !!block.module,
55+
// vite handle CSS modules
56+
modules: !!block.module && !options.vite,
5657
postcssOptions: options.postcssOptions,
5758
postcssPlugins: options.postcssPlugins,
5859
modulesOptions: options.cssModulesOptions,
@@ -62,16 +63,21 @@ export async function transformStyle(
6263
})
6364

6465
if (result.errors.length) {
65-
result.errors.forEach((error) =>
66-
pluginContext.error({
67-
id: query.filename,
68-
message: error.message,
69-
})
70-
)
66+
result.errors.forEach((error: any) => {
67+
if (error.line && error.column) {
68+
error.loc = {
69+
file: query.filename,
70+
line: error.line + block.loc.start.line,
71+
column: error.column,
72+
}
73+
}
74+
pluginContext.error(error)
75+
})
7176
return null
7277
}
7378

74-
if (query.module) {
79+
if (query.module && !options.vite) {
80+
// vite handles css modules code generation down the stream
7581
return {
7682
code: `export default ${JSON.stringify(result.modules)}`,
7783
map: null,

src/utils/error.ts

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export function createRollupError(
55
id: string,
66
error: CompilerError | SyntaxError
77
): RollupError {
8-
debugger
98
if ('code' in error) {
109
return {
1110
id,

0 commit comments

Comments
 (0)