Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(css): deprecate css default export #11094

Merged
merged 10 commits into from Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/vite/client.d.ts
Expand Up @@ -38,34 +38,58 @@ declare module '*.module.sss' {

// CSS
declare module '*.css' {
/**
* @deprecated Use `import style from './style.css?inline'` instead.
*/
const css: string
export default css
}
declare module '*.scss' {
/**
* @deprecated Use `import style from './style.scss?inline'` instead.
*/
const css: string
export default css
}
declare module '*.sass' {
/**
* @deprecated Use `import style from './style.sass?inline'` instead.
*/
const css: string
export default css
}
declare module '*.less' {
/**
* @deprecated Use `import style from './style.less?inline'` instead.
*/
const css: string
export default css
}
declare module '*.styl' {
/**
* @deprecated Use `import style from './style.styl?inline'` instead.
*/
const css: string
export default css
}
declare module '*.stylus' {
/**
* @deprecated Use `import style from './style.stylus?inline'` instead.
*/
const css: string
export default css
}
declare module '*.pcss' {
/**
* @deprecated Use `import style from './style.pcss?inline'` instead.
*/
const css: string
export default css
}
declare module '*.sss' {
/**
* @deprecated Use `import style from './style.sss?inline'` instead.
*/
const css: string
export default css
}
Expand Down
Expand Up @@ -4,12 +4,14 @@ import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
import { transformGlobImport } from '../../../plugins/importMetaGlob'
import { transformWithEsbuild } from '../../../plugins/esbuild'
import { createLogger } from '../../../logger'

const __dirname = resolve(fileURLToPath(import.meta.url), '..')

describe('fixture', async () => {
const resolveId = (id: string) => id
const root = resolve(__dirname, '..')
const logger = createLogger()

it('transform', async () => {
const id = resolve(__dirname, './fixture-a/index.ts')
Expand All @@ -18,7 +20,9 @@ describe('fixture', async () => {
).code

expect(
(await transformGlobImport(code, id, root, resolveId))?.s.toString()
(
await transformGlobImport(code, id, root, resolveId, logger)
)?.s.toString()
).toMatchSnapshot()
})

Expand All @@ -30,7 +34,13 @@ describe('fixture', async () => {
].join('\n')
expect(
(
await transformGlobImport(code, 'virtual:module', root, resolveId)
await transformGlobImport(
code,
'virtual:module',
root,
resolveId,
logger
)
)?.s.toString()
).toMatchSnapshot()

Expand All @@ -39,7 +49,8 @@ describe('fixture', async () => {
"import.meta.glob('./modules/*.ts')",
'virtual:module',
root,
resolveId
resolveId,
logger
)
expect('no error').toBe('should throw an error')
} catch (err) {
Expand All @@ -56,7 +67,9 @@ describe('fixture', async () => {
).code

expect(
(await transformGlobImport(code, id, root, resolveId, true))?.s.toString()
(
await transformGlobImport(code, id, root, resolveId, logger, true)
)?.s.toString()
).toMatchSnapshot()
})
})
3 changes: 3 additions & 0 deletions packages/vite/src/node/constants.ts
Expand Up @@ -46,6 +46,9 @@ export const DEFAULT_CONFIG_FILES = [

export const JS_TYPES_RE = /\.(?:j|t)sx?$|\.mjs$/

export const CSS_LANGS_RE =
/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)($|\\?)/

export const OPTIMIZABLE_ENTRY_RE = /\.[cm]?[jt]s$/

export const SPECIAL_QUERY_RE = /[?&](?:worker|sharedworker|raw|url)\b/
Expand Down
23 changes: 13 additions & 10 deletions packages/vite/src/node/optimizer/scan.ts
Expand Up @@ -6,7 +6,12 @@ import type { Loader, OnLoadResult, Plugin } from 'esbuild'
import { build, transform } from 'esbuild'
import colors from 'picocolors'
import type { ResolvedConfig } from '..'
import { JS_TYPES_RE, KNOWN_ASSET_TYPES, SPECIAL_QUERY_RE } from '../constants'
import {
CSS_LANGS_RE,
JS_TYPES_RE,
KNOWN_ASSET_TYPES,
SPECIAL_QUERY_RE
} from '../constants'
import {
cleanUrl,
createDebugger,
Expand Down Expand Up @@ -217,7 +222,8 @@ function esbuildScanPlugin(
transpiledContents,
id,
config.root,
resolve
resolve,
config.logger
)

return result?.s.toString() || transpiledContents
Expand Down Expand Up @@ -430,14 +436,11 @@ function esbuildScanPlugin(
// they are done after the bare import resolve because a package name
// may end with these extensions

// css & json & wasm
build.onResolve(
{
filter:
/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss|json|wasm)$/
},
externalUnlessEntry
)
// css
build.onResolve({ filter: CSS_LANGS_RE }, externalUnlessEntry)

// json & wasm
build.onResolve({ filter: /\.(json|json5|wasm)$/ }, externalUnlessEntry)

// known asset types
build.onResolve(
Expand Down
20 changes: 12 additions & 8 deletions packages/vite/src/node/plugins/css.ts
Expand Up @@ -26,7 +26,11 @@ import { getCodeWithSourcemap, injectSourcesContent } from '../server/sourcemap'
import type { ModuleNode } from '../server/moduleGraph'
import type { ResolveFn, ViteDevServer } from '../'
import { toOutputFilePathInCss } from '../build'
import { CLIENT_PUBLIC_PATH, SPECIAL_QUERY_RE } from '../constants'
import {
CLIENT_PUBLIC_PATH,
CSS_LANGS_RE,
SPECIAL_QUERY_RE
} from '../constants'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import {
Expand Down Expand Up @@ -102,10 +106,7 @@ export interface CSSModulesOptions {
localsConvention?: 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly'
}

const cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)($|\\?)`
const cssLangRE = new RegExp(cssLangs)
// eslint-disable-next-line regexp/no-unused-capturing-group
const cssModuleRE = new RegExp(`\\.module${cssLangs}`)
const cssModuleRE = new RegExp(`\\.module${CSS_LANGS_RE.source}`)
const directRequestRE = /(?:\?|&)direct\b/
const htmlProxyRE = /(?:\?|&)html-proxy\b/
const commonjsProxyRE = /\?commonjs-proxy/
Expand Down Expand Up @@ -135,10 +136,13 @@ type CssLang =
| keyof typeof PostCssDialectLang

export const isCSSRequest = (request: string): boolean =>
cssLangRE.test(request)
CSS_LANGS_RE.test(request)

export const isModuleCSSRequest = (request: string): boolean =>
cssModuleRE.test(request)

export const isDirectCSSRequest = (request: string): boolean =>
cssLangRE.test(request) && directRequestRE.test(request)
CSS_LANGS_RE.test(request) && directRequestRE.test(request)

export const isDirectRequest = (request: string): boolean =>
directRequestRE.test(request)
Expand Down Expand Up @@ -773,7 +777,7 @@ async function compileCSS(
// crawl them in order to register watch dependencies.
const needInlineImport = code.includes('@import')
const hasUrl = cssUrlRE.test(code) || cssImageSetRE.test(code)
const lang = id.match(cssLangRE)?.[1] as CssLang | undefined
const lang = id.match(CSS_LANGS_RE)?.[1] as CssLang | undefined
const postcssConfig = await resolvePostcssConfig(config, getCssDialect(lang))

// 1. plain css that needs no processing
Expand Down
49 changes: 40 additions & 9 deletions packages/vite/src/node/plugins/importAnalysis.ts
Expand Up @@ -63,7 +63,7 @@ import {
ERR_OUTDATED_OPTIMIZED_DEP,
throwOutdatedRequest
} from './optimizedDeps'
import { isCSSRequest, isDirectCSSRequest } from './css'
import { isCSSRequest, isDirectCSSRequest, isModuleCSSRequest } from './css'
import { browserExternalId } from './resolve'

const isDebug = !!process.env.DEBUG
Expand Down Expand Up @@ -436,6 +436,35 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
str().remove(end + 1, expEnd)
}

if (
!isDynamicImport &&
specifier &&
isCSSRequest(specifier) &&
!isModuleCSSRequest(specifier) &&
!specifier.includes('?') // ignore custom queries
) {
const sourceExp = source.slice(expStart, start)
if (
sourceExp.includes('from') && // check default and named imports
!sourceExp.includes('__vite_glob_') // glob handles deprecation message itself
) {
const newImport =
sourceExp + specifier + `?inline` + source.slice(end, expEnd)
this.warn(
`\n` +
colors.cyan(importerModule.file) +
`\n` +
colors.reset(generateCodeFrame(source, start)) +
`\n` +
colors.yellow(
`Default and named imports from CSS files are deprecated. ` +
`Use the ?inline query instead. ` +
`For example: ${newImport}`
)
)
}
}

// static import or valid string in dynamic import
// If resolvable, let's resolve it
if (specifier) {
Expand Down Expand Up @@ -567,14 +596,16 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
`\n` +
colors.cyan(importerModule.file) +
`\n` +
generateCodeFrame(source, start) +
`\nThe above dynamic import cannot be analyzed by Vite.\n` +
`See ${colors.blue(
`https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations`
)} ` +
`for supported dynamic import formats. ` +
`If this is intended to be left as-is, you can use the ` +
`/* @vite-ignore */ comment inside the import() call to suppress this warning.\n`
colors.reset(generateCodeFrame(source, start)) +
colors.yellow(
`\nThe above dynamic import cannot be analyzed by Vite.\n` +
`See ${colors.blue(
`https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations`
)} ` +
`for supported dynamic import formats. ` +
`If this is intended to be left as-is, you can use the ` +
`/* @vite-ignore */ comment inside the import() call to suppress this warning.\n`
)
)
}
}
Expand Down
29 changes: 28 additions & 1 deletion packages/vite/src/node/plugins/importMetaGlob.ts
@@ -1,5 +1,6 @@
import { isAbsolute, posix } from 'node:path'
import micromatch from 'micromatch'
import colors from 'picocolors'
import { stripLiteral } from 'strip-literal'
import type {
ArrayExpression,
Expand All @@ -21,7 +22,14 @@ import type { Plugin } from '../plugin'
import type { ViteDevServer } from '../server'
import type { ModuleNode } from '../server/moduleGraph'
import type { ResolvedConfig } from '../config'
import { normalizePath, slash, transformStableResult } from '../utils'
import {
generateCodeFrame,
normalizePath,
slash,
transformStableResult
} from '../utils'
import type { Logger } from '../logger'
import { isCSSRequest } from './css'

const { isMatch, scan } = micromatch

Expand Down Expand Up @@ -68,6 +76,7 @@ export function importGlobPlugin(config: ResolvedConfig): Plugin {
id,
config.root,
(im) => this.resolve(im, id).then((i) => i?.id || im),
config.logger,
config.experimental.importGlobRestoreExtension
)
if (result) {
Expand Down Expand Up @@ -318,6 +327,7 @@ export async function transformGlobImport(
id: string,
root: string,
resolveId: IdResolver,
logger: Logger,
restoreQueryExtension = false
): Promise<TransformGlobImportResult | null> {
id = slash(id)
Expand Down Expand Up @@ -374,6 +384,23 @@ export async function transformGlobImport(

if (query && !query.startsWith('?')) query = `?${query}`

if (
!query.match(/(?:\?|&)inline\b/) &&
files.some((file) => isCSSRequest(file))
) {
logger.warn(
`\n` +
colors.cyan(id) +
`\n` +
colors.reset(generateCodeFrame(code, start)) +
`\n` +
colors.yellow(
`Globbing CSS files without the ?inline query is deprecated. ` +
`Add the \`{ query: '?inline' }\` glob option to fix this.`
)
)
}

const resolvePaths = (file: string) => {
if (!dir) {
if (isRelative)
Expand Down
9 changes: 6 additions & 3 deletions packages/vite/src/node/plugins/splitVendorChunk.ts
Expand Up @@ -8,10 +8,13 @@ import type { UserConfig } from '../../node'
import type { Plugin } from '../plugin'

// This file will be built for both ESM and CJS. Avoid relying on other modules as possible.
const cssLangs = `\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)`
const cssLangRE = new RegExp(cssLangs)

// copy from constants.ts
const CSS_LANGS_RE =
// eslint-disable-next-line regexp/no-unused-capturing-group
/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\\?)/
export const isCSSRequest = (request: string): boolean =>
cssLangRE.test(request)
CSS_LANGS_RE.test(request)

// Use splitVendorChunkPlugin() to get the same manualChunks strategy as Vite 2.7
// We don't recommend using this strategy as a general solution moving forward
Expand Down
12 changes: 7 additions & 5 deletions playground/css/__tests__/css.spec.ts
Expand Up @@ -17,16 +17,18 @@ import {
// note: tests should retrieve the element at the beginning of test and reuse it
// in later assertions to ensure CSS HMR doesn't reload the page
test('imported css', async () => {
const glob = await page.textContent('.imported-css-glob')
expect(glob).toContain('.dir-import')
const globEager = await page.textContent('.imported-css-globEager')
expect(globEager).toContain('.dir-import')
})

test('inline imported css', async () => {
const css = await page.textContent('.imported-css')
expect(css).toMatch(/\.imported ?\{/)
if (isBuild) {
expect(css.trim()).not.toContain('\n') // check minified
}

const glob = await page.textContent('.imported-css-glob')
expect(glob).toContain('.dir-import')
const globEager = await page.textContent('.imported-css-globEager')
expect(globEager).toContain('.dir-import')
})

test('linked css', async () => {
Expand Down