Skip to content

Commit

Permalink
feat: remove styles: 'expose'
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Removed `styles: 'expose'` option
  • Loading branch information
KaelWD committed Dec 12, 2023
1 parent c4ead73 commit c43dc80
Show file tree
Hide file tree
Showing 5 changed files with 7 additions and 280 deletions.
4 changes: 1 addition & 3 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import * as path from 'upath'

export interface Options {
autoImport?: importPluginOptions,
styles?: true | 'none' | 'expose' | 'sass' | {
styles?: true | 'none' | 'sass' | {
configFile: string,
},
/** @internal Only for testing */
stylesTimeout?: number
}

export type importPluginOptions =
Expand Down
3 changes: 1 addition & 2 deletions packages/vite-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ function vuetify (_options: Options = {}): Plugin[] {
const options: Options = {
autoImport: true,
styles: true,
stylesTimeout: 1000,
..._options,
}

const plugins: Plugin[] = []
if (options.autoImport) {
plugins.push(importPlugin())
}
if (includes(['none', 'expose', 'sass'], options.styles) || isObject(options.styles)) {
if (includes(['none', 'sass'], options.styles) || isObject(options.styles)) {
plugins.push(stylesPlugin(options))
}

Expand Down
159 changes: 2 additions & 157 deletions packages/vite-plugin/src/stylesPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,145 +1,23 @@
import { utimes } from 'fs/promises'
import * as path from 'upath'
import _debug from 'debug'
import { normalizePath as normalizeVitePath } from 'vite'
import { cacheDir, writeStyles, resolveVuetifyBase, normalizePath } from '@vuetify/loader-shared'
import { resolveVuetifyBase, normalizePath } from '@vuetify/loader-shared'

import type { Plugin, ViteDevServer } from 'vite'
import type { Plugin } from 'vite'
import type { Options } from '@vuetify/loader-shared'
import type { PluginContext } from 'rollup'

const debug = _debug('vuetify:styles')

function isSubdir (root: string, test: string) {
const relative = path.relative(root, test)
return relative && !relative.startsWith('..') && !path.isAbsolute(relative)
}

const styleImportRegexp = /(@use |meta\.load-css\()['"](vuetify(?:\/lib)?(?:\/styles(?:\/main(?:\.sass)?)?)?)['"]/

export function stylesPlugin (options: Options): Plugin {
const vuetifyBase = resolveVuetifyBase()
const files = new Set<string>()

let server: ViteDevServer
let context: PluginContext
let resolve: (v: boolean) => void
let promise: Promise<boolean> | null
let needsTouch = false
const blockingModules = new Set<string>()

let pendingModules: string[]
async function getPendingModules () {
if (!server) {
await new Promise(resolve => setTimeout(resolve, 0))
const modules = Array.from(context.getModuleIds())
.filter(id => {
return !blockingModules.has(id) && // Ignore the current file
!/\w\.(s[ac]|c)ss/.test(id) // Ignore stylesheets
})
.map(id => context.getModuleInfo(id)!)
.filter(module => module.code == null) // Ignore already loaded modules

pendingModules = modules.map(module => module.id)
if (!pendingModules.length) return 0

const promises = modules.map(module => context.load(module))
await Promise.race(promises)

return promises.length
} else {
const modules = Array.from(server.moduleGraph.urlToModuleMap.entries())
.filter(([k, v]) => (
v.transformResult == null && // Ignore already loaded modules
!k.startsWith('/@id/') &&
!/\w\.(s[ac]|c)ss/.test(k) && // Ignore stylesheets
!blockingModules.has(v.id!) && // Ignore the current file
!/\/node_modules\/\.vite\/deps\/(?!vuetify[._])/.test(k) // Ignore dependencies
))

pendingModules = modules.map(([, v]) => v.id!)
if (!pendingModules.length) return 0

const promises = modules.map(([k, v]) => server.transformRequest(k).then(() => v))
await Promise.race(promises)

return promises.length
}
}

let timeout: NodeJS.Timeout
async function awaitBlocking () {
let pending
do {
clearTimeout(timeout)
timeout = setTimeout(() => {
console.error('vuetify:styles fallback timeout hit', {
blockingModules: Array.from(blockingModules.values()),
pendingModules,
pendingRequests: server?._pendingRequests.keys()
})
resolve(false)
}, options.stylesTimeout)

pending = await Promise.any<boolean | number | null>([
promise,
getPendingModules()
])
debug(pending, 'pending modules', pendingModules)
} while (pending)

resolve(false)
}

async function awaitResolve (id?: string) {
if (id) {
blockingModules.add(id)
}

if (!promise) {
promise = new Promise((_resolve) => resolve = _resolve)

awaitBlocking()
await promise
clearTimeout(timeout)
blockingModules.clear()

debug('writing styles')
await writeStyles(files)

if (server && needsTouch) {
const cacheFile = normalizeVitePath(cacheDir('styles.scss'))
server.moduleGraph.getModulesByFile(cacheFile)?.forEach(module => {
module.importers.forEach(module => {
if (module.file) {
const now = new Date()
debug(`touching ${module.file}`)
utimes(module.file, now, now)
}
})
})
needsTouch = false
}
promise = null
}

return promise
}

let configFile: string
const tempFiles = new Map<string, string>()

return {
name: 'vuetify:styles',
enforce: 'pre',
configureServer (_server) {
server = _server
},
buildStart () {
if (!server) {
context = this
}
},
configResolved (config) {
if (typeof options.styles === 'object') {
if (path.isAbsolute(options.styles.configFile)) {
Expand All @@ -162,23 +40,6 @@ export function stylesPlugin (options: Options): Plugin {
} else if (options.styles === 'sass') {
const target = source.replace(/\.css$/, '.sass')
return this.resolve(target, importer, { skipSelf: true, custom })
} else if (options.styles === 'expose') {
awaitResolve()

const resolution = await this.resolve(
source.replace(/\.css$/, '.sass'),
importer,
{ skipSelf: true, custom }
)

if (resolution) {
if (!files.has(resolution.id)) {
needsTouch = true
files.add(resolution.id)
}

return '\0__void__'
}
} else if (typeof options.styles === 'object') {
const resolution = await this.resolve(source, importer, { skipSelf: true, custom })

Expand All @@ -200,22 +61,6 @@ export function stylesPlugin (options: Options): Plugin {

return null
},
async transform (code, id) {
if (
options.styles === 'expose' &&
['.scss', '.sass'].some(v => id.endsWith(v)) &&
styleImportRegexp.test(code)
) {
debug(`awaiting ${id}`)
await awaitResolve(id)
debug(`returning ${id}`)

return {
code: code.replace(styleImportRegexp, '$1".cache/vuetify/styles.scss"'),
map: null,
}
}
},
load (id) {
// When Vite is configured with `optimizeDeps.exclude: ['vuetify']`, the
// received id contains a version hash (e.g. \0__void__?v=893fa859).
Expand Down
105 changes: 3 additions & 102 deletions packages/webpack-plugin/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ import * as mkdirp from 'mkdirp'

import {
resolveVuetifyBase,
writeStyles,
includes,
isObject,
cacheDir,
transformAssetUrls,
normalizePath,
} from '@vuetify/loader-shared'

import type { Compiler, NormalModule, Module } from 'webpack'
import type { Compiler } from 'webpack'
import type { Options } from '@vuetify/loader-shared'

function isSubdir (root: string, test: string) {
Expand All @@ -29,7 +27,6 @@ export class VuetifyPlugin {
this.options = {
autoImport: true,
styles: true,
stylesTimeout: 10000,
...options,
}
}
Expand Down Expand Up @@ -75,7 +72,7 @@ export class VuetifyPlugin {
})
}

if (includes(['none', 'expose'], this.options.styles)) {
if (this.options.styles === 'none') {
compiler.options.module.rules.push({
enforce: 'pre',
test: /\.css$/,
Expand All @@ -87,103 +84,7 @@ export class VuetifyPlugin {
hookResolve(file => file.replace(/\.css$/, '.sass'))
}

if (this.options.styles === 'expose') {
const files = new Set<string>()
let resolve: (v: boolean) => void
let promise: Promise<boolean> | null
let timeout: NodeJS.Timeout

const blockingModules = new Set<string>()
const pendingModules = new Map<string, Module>()
compiler.hooks.compilation.tap('vuetify-loader', (compilation) => {
compilation.hooks.buildModule.tap('vuetify-loader', (module) => {
pendingModules.set((module as NormalModule).request, module)
})
compilation.hooks.succeedModule.tap('vuetify-loader', (module) => {
pendingModules.delete((module as NormalModule).request)
if (
resolve &&
!Array.from(pendingModules.keys()).filter(k => !blockingModules.has(k)).length
) {
resolve(false)
}
})
})

const logger = compiler.getInfrastructureLogger('vuetify-loader')
const awaitResolve = async (id?: string) => {
if (id) {
blockingModules.add(id)
}

if (!promise) {
promise = new Promise((_resolve) => resolve = _resolve)

clearTimeout(timeout)
timeout = setTimeout(() => {
logger.error('styles fallback timeout hit', {
blockingModules: Array.from(blockingModules.values()),
pendingModules: Array.from(pendingModules.values(), module => (module as NormalModule).resource),
})
resolve(false)
}, this.options.stylesTimeout)

if (!Array.from(pendingModules.keys()).filter(k => !blockingModules.has(k)).length) {
resolve(false)
}

const start = files.size
await promise
clearTimeout(timeout)
blockingModules.clear()

if (files.size > start) {
await writeStyles(files)
}
promise = null
}

return promise
}

compiler.options.module.rules.push({
enforce: 'pre',
test: /\.s[ac]ss$/,
loader: require.resolve('./styleLoader'),
options: { awaitResolve },
})

compiler.options.resolve.plugins = compiler.options.resolve.plugins || []
compiler.options.resolve.plugins.push({
apply (resolver) {
resolver
.getHook('resolve')
.tapAsync('vuetify-loader', async (request, context, callback) => {
if (!(
request.path &&
request.request?.endsWith('.css') &&
isSubdir(vuetifyBase, request.path)
)) {
return callback()
}

resolver.resolve(
{},
request.path,
request.request.replace(/\.css$/, '.sass'),
context,
(err, resolution) => {
if (resolution && !files.has(resolution)) {
awaitResolve()
files.add(resolution)
}
return callback()
}
)
})
}
})
} else if (isObject(this.options.styles)) {
if (isObject(this.options.styles)) {
const configFile = path.isAbsolute(this.options.styles.configFile)
? this.options.styles.configFile
: path.join(
Expand Down
16 changes: 0 additions & 16 deletions packages/webpack-plugin/src/styleLoader.ts

This file was deleted.

0 comments on commit c43dc80

Please sign in to comment.