Skip to content

Commit

Permalink
feat: proper css resolving + sass import url rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jan 26, 2021
1 parent 1dfda16 commit 477f174
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 153 deletions.
4 changes: 3 additions & 1 deletion packages/playground/css/__tests__/css.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'path'
import {
editFile,
findAssetFile,
getBg,
getColor,
isBuild,
testDir,
Expand Down Expand Up @@ -58,13 +59,14 @@ test('sass', async () => {

expect(await getColor(imported)).toBe('orange')
expect(await getColor(atImport)).toBe('olive')
expect(await getBg(atImport)).toMatch(isBuild ? /base64/ : '/nested/icon.png')

editFile('sass.scss', (code) =>
code.replace('color: $injectedColor', 'color: red')
)
await untilUpdated(() => getColor(imported), 'red')

editFile('sass-at-import.scss', (code) =>
editFile('nested/_index.scss', (code) =>
code.replace('color: olive', 'color: blue')
)
await untilUpdated(() => getColor(atImport), 'blue')
Expand Down
4 changes: 3 additions & 1 deletion packages/playground/css/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ <h1>CSS</h1>
</p>

<p class="sass">sass: This should be orange</p>
<p class="sass-at-import">@import from SASS: This should be olive</p>
<p class="sass-at-import">
@import from SASS: This should be olive and have bg image
</p>
<p>Imported SASS string:</p>
<pre class="imported-sass"></pre>

Expand Down
4 changes: 4 additions & 0 deletions packages/playground/css/nested/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.sass-at-import {
color: olive;
background: url(./icon.png) 10px no-repeat;
}
Binary file added packages/playground/css/nested/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions packages/playground/css/sass-at-import.scss

This file was deleted.

2 changes: 1 addition & 1 deletion packages/playground/css/sass.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import './sass-at-import.scss';
@import '@/nested'; // alias + custom index resolving -> /nested/_index.scss

.sass {
/* injected via vite.config.js */
Expand Down
65 changes: 54 additions & 11 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,26 @@ export type ResolvedConfig = Readonly<
optimizeCacheDir: string | undefined
env: Record<string, any>
alias: Alias[]
aliasResolver: PluginContainer
plugins: readonly Plugin[]
server: ServerOptions
build: ResolvedBuildOptions
assetsInclude: (file: string) => boolean
logger: Logger
base: string
createResolver: (options?: {
asSrc?: boolean
tryIndex?: boolean | string
extensions?: string[]
}) => ResolveFn
}
>

export type ResolveFn = (
id: string,
importer?: string,
aliasOnly?: boolean
) => Promise<string | undefined>

export async function resolveConfig(
inlineConfig: InlineConfig,
command: 'build' | 'serve',
Expand Down Expand Up @@ -285,7 +295,44 @@ export async function resolveConfig(
? createFilter(config.assetsInclude)
: () => false

const resolved = {
// create an internal resolver to be used in special scenarios, e.g.
// optimizer & handling css @imports
const createResolver: ResolvedConfig['createResolver'] = (options) => {
let aliasContainer: PluginContainer | undefined
let resolverContainer: PluginContainer | undefined
return async (id, importer, aliasOnly) => {
let container: PluginContainer
if (aliasOnly) {
container =
aliasContainer ||
(aliasContainer = await createPluginContainer({
...resolved,
plugins: [aliasPlugin({ entries: resolved.alias })]
}))
} else {
container =
resolverContainer ||
(resolverContainer = await createPluginContainer({
...resolved,
plugins: [
aliasPlugin({ entries: resolved.alias }),
resolvePlugin({
root: resolvedRoot,
dedupe: resolved.dedupe,
isProduction,
isBuild: command === 'build',
asSrc: options?.asSrc || true,
tryIndex: options?.tryIndex || true,
extensions: options?.extensions
})
]
}))
}
return (await container.resolveId(id, importer))?.id
}
}

const resolved: ResolvedConfig = {
...config,
configFile: configFile ? normalizePath(configFile) : undefined,
inlineConfig,
Expand All @@ -295,7 +342,6 @@ export async function resolveConfig(
isProduction,
optimizeCacheDir,
alias: resolvedAlias,
aliasResolver: null as any,
plugins: userPlugins,
server: config.server || {},
build: resolvedBuildOptions,
Expand All @@ -310,21 +356,17 @@ export async function resolveConfig(
return DEFAULT_ASSETS_RE.test(file) || assetsFilter(file)
},
logger,
base: BASE_URL
base: BASE_URL,
createResolver
}

resolved.plugins = await resolvePlugins(
;(resolved as any).plugins = await resolvePlugins(
resolved,
prePlugins,
normalPlugins,
postPlugins
)

resolved.aliasResolver = await createPluginContainer({
...resolved,
plugins: [aliasPlugin({ entries: config.alias })]
})

// call configResolved hooks
userPlugins.forEach((p) => {
if (p.configResolved) {
Expand Down Expand Up @@ -626,7 +668,8 @@ async function bundleConfigFile(
resolvePlugin({
root: path.dirname(fileName),
isBuild: true,
asSrc: false
asSrc: false,
isProduction: false
}),
{
name: 'replace-import-meta',
Expand Down
25 changes: 4 additions & 21 deletions packages/vite/src/node/optimizer/esbuildDepPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import path from 'path'
import { Plugin } from 'esbuild'
import { knownAssetTypes } from '../constants'
import { ResolvedConfig } from '..'
import { ResolvedConfig, ResolveFn } from '..'
import chalk from 'chalk'
import { deepImportRE, isBuiltin, isRunningWithYarnPnp } from '../utils'
import { tryNodeResolve } from '../plugins/resolve'
import { PluginContainer } from '../server/pluginContainer'

const externalTypes = [
'css',
Expand All @@ -25,26 +23,11 @@ export function esbuildDepPlugin(
qualified: Record<string, string>,
config: ResolvedConfig,
transitiveOptimized: Record<string, true>,
aliasResolver: PluginContainer
resolve: ResolveFn
): Plugin {
return {
name: 'vite:dep-pre-bundle',
setup(build) {
async function useViteResolve(id: string, importer: string) {
id = (await aliasResolver.resolveId(id))?.id || id
const resolved = tryNodeResolve(
id,
path.dirname(importer),
false,
true,
config.dedupe,
config.root
)
if (resolved) {
return path.resolve(resolved.id)
}
}

// externalize assets and commonly known non-js file types
build.onResolve(
{
Expand All @@ -58,7 +41,7 @@ export function esbuildDepPlugin(
external: true
}
} else {
const resolved = await useViteResolve(id, importer)
const resolved = await resolve(id, importer)
if (resolved) {
return {
path: resolved,
Expand All @@ -82,7 +65,7 @@ export function esbuildDepPlugin(
const pkgId = deepMatch ? deepMatch[1] || deepMatch[2] : id
transitiveOptimized[pkgId] = true
// use vite resolver
const resolved = await useViteResolve(id, importer)
const resolved = await resolve(id, importer)
if (resolved) {
return {
path: resolved
Expand Down
42 changes: 13 additions & 29 deletions packages/vite/src/node/optimizer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ import {
resolveFrom,
writeFile
} from '../utils'
import { PluginContainer } from '../server/pluginContainer'
import { tryNodeResolve } from '../plugins/resolve'
import { createFilter } from '@rollup/pluginutils'
import { prompt } from 'enquirer'
import { build } from 'esbuild'
import { esbuildDepPlugin } from './esbuildDepPlugin'
import { init, parse } from 'es-module-lexer'
import { ResolveFn } from '..'

const debug = createDebugger('vite:optimize')

Expand Down Expand Up @@ -119,7 +118,7 @@ export async function optimizeDeps(
}

const options = config.optimizeDeps || {}
const aliasResolver = config.aliasResolver
const resolve = config.createResolver({ asSrc: false })

// Determine deps to optimize. The goal is to only pre-bundle deps that falls
// under one of the following categories:
Expand All @@ -129,7 +128,7 @@ export async function optimizeDeps(
const { qualified, external } = await resolveQualifiedDeps(
root,
config,
aliasResolver
resolve
)

// Resolve deps from linked packages in a monorepo
Expand All @@ -141,18 +140,17 @@ export async function optimizeDeps(
qualified,
external,
config,
aliasResolver
resolve
)
}
}

// Force included deps - these can also be deep paths
if (options.include) {
for (let id of options.include) {
const aliased = (await aliasResolver.resolveId(id))?.id || id
const filePath = tryNodeResolve(aliased, root, config.isProduction)
const filePath = await resolve(id)
if (filePath) {
qualified[id] = filePath.id
qualified[id] = filePath
}
}
}
Expand Down Expand Up @@ -240,12 +238,7 @@ export async function optimizeDeps(
'process.env.NODE_ENV': '"development"'
},
plugins: [
esbuildDepPlugin(
qualified,
config,
data.transitiveOptimized,
aliasResolver
)
esbuildDepPlugin(qualified, config, data.transitiveOptimized, resolve)
]
})

Expand Down Expand Up @@ -326,7 +319,7 @@ interface FilteredDeps {
async function resolveQualifiedDeps(
root: string,
config: ResolvedConfig,
aliasResolver: PluginContainer
resolve: ResolveFn
): Promise<FilteredDeps> {
const { include, exclude, link } = config.optimizeDeps || {}
const qualified: Record<string, string> = {}
Expand Down Expand Up @@ -366,9 +359,7 @@ async function resolveQualifiedDeps(
}
let filePath
try {
const aliased = (await aliasResolver.resolveId(id))?.id || id
const resolved = tryNodeResolve(aliased, root, config.isProduction)
filePath = resolved && resolved.id
filePath = await resolve(id)
} catch (e) {}
if (!filePath) {
debug(`skipping ${id} (cannot resolve entry)`)
Expand All @@ -395,20 +386,13 @@ async function resolveQualifiedDeps(
.filter((id) => !qualified[id])
// make sure aliased deps are external
// https://github.com/vitejs/vite-plugin-react/issues/4
.map(async (id) => (await aliasResolver.resolveId(id))?.id || id)
.map(async (id) => (await resolve(id, undefined, true)) || id)
))
)

if (linked.length) {
for (const dep of linked) {
await resolveLinkedDeps(
root,
dep,
qualified,
external,
config,
aliasResolver
)
await resolveLinkedDeps(root, dep, qualified, external, config, resolve)
}
}

Expand All @@ -424,13 +408,13 @@ async function resolveLinkedDeps(
qualified: Record<string, string>,
external: string[],
config: ResolvedConfig,
aliasResolver: PluginContainer
resolve: ResolveFn
) {
const depRoot = path.dirname(resolveFrom(`${dep}/package.json`, root))
const { qualified: q, external: e } = await resolveQualifiedDeps(
depRoot,
config,
aliasResolver
resolve
)
Object.keys(q).forEach((id) => {
if (!qualified[id]) {
Expand Down
Loading

0 comments on commit 477f174

Please sign in to comment.