From ad50060ed43c8d84c22a5c60592404a4e1180e2d Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 16 Feb 2021 10:43:01 -0500 Subject: [PATCH] fix(css/assets): respect alias in css url() paths close #2043 --- .../assets/__tests__/assets.spec.ts | 5 ++ packages/playground/assets/css/css-url.css | 8 ++- packages/playground/assets/index.html | 3 + packages/playground/assets/vite.config.js | 7 ++ packages/vite/src/node/plugins/asset.ts | 2 +- packages/vite/src/node/plugins/css.ts | 71 ++++++++++++------- 6 files changed, 68 insertions(+), 28 deletions(-) diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts index 04ba14afa17272..e5f7c6af1ff777 100644 --- a/packages/playground/assets/__tests__/assets.spec.ts +++ b/packages/playground/assets/__tests__/assets.spec.ts @@ -105,6 +105,11 @@ describe('css url() references', () => { expect(bg).toMatch(iconMatch) }) + test('aliased', async () => { + const bg = await getBg('.css-url-aliased') + expect(bg).toMatch(assetMatch) + }) + if (isBuild) { test('preserve postfix query/hash', () => { expect(findAssetFile(/\.css$/, 'foo')).toMatch(`woff2?#iefix`) diff --git a/packages/playground/assets/css/css-url.css b/packages/playground/assets/css/css-url.css index 683305fa687b95..ae2dff3f633405 100644 --- a/packages/playground/assets/css/css-url.css +++ b/packages/playground/assets/css/css-url.css @@ -31,7 +31,13 @@ } .css-url-same-line { - background: url('/nested/asset.png') top right / 10px no-repeat, url('/icon.png') bottom right / 10px no-repeat; + background: url('/nested/asset.png') top right / 10px no-repeat, + url('/icon.png') bottom right / 10px no-repeat; +} + +.css-url-aliased { + background: url('@/asset.png'); + background-size: 10px; } /* diff --git a/packages/playground/assets/index.html b/packages/playground/assets/index.html index eeed653201796c..1819dcf2b69a21 100644 --- a/packages/playground/assets/index.html +++ b/packages/playground/assets/index.html @@ -52,6 +52,9 @@

CSS url references

>CSS background (multiple urls on same line) +
+ CSS background (aliased) +

SVG Fragments

diff --git a/packages/playground/assets/vite.config.js b/packages/playground/assets/vite.config.js index 10096153d865d2..113191c246a4a8 100644 --- a/packages/playground/assets/vite.config.js +++ b/packages/playground/assets/vite.config.js @@ -1,9 +1,16 @@ +const path = require('path') + /** * @type {import('vite').UserConfig} */ module.exports = { base: '/foo/', publicDir: 'static', + resolve: { + alias: { + '@': path.resolve(__dirname, 'nested') + } + }, build: { outDir: 'dist/foo', manifest: true diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 7d368627aec5bb..0e426fd6e5d934 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -140,7 +140,7 @@ export function fileToUrl( } } -export function fileToDevUrl(id: string, config: ResolvedConfig) { +function fileToDevUrl(id: string, config: ResolvedConfig) { let rtn: string if (checkPublicFile(id, config)) { // in public dir, keep the url as-is diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 700eb90f90014b..c5bfdb97e1e5f8 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -27,9 +27,9 @@ import { ResolveFn, ViteDevServer } from '../' import { getAssetFilename, assetUrlRE, - fileToDevUrl, registerAssetToChunk, - urlToBuiltUrl + fileToUrl, + checkPublicFile } from './asset' import MagicString from 'magic-string' import * as Postcss from 'postcss' @@ -103,7 +103,12 @@ export function cssPlugin(config: ResolvedConfig): Plugin { const moduleCache = new Map>() cssModulesCache.set(config, moduleCache) - const resolvers = createCSSResolvers(config) + const resolveUrl = config.createResolver({ + preferRelative: true, + tryIndex: false, + extensions: [] + }) + const atImportResolvers = createCSSResolvers(config) return { name: 'vite:css', @@ -117,27 +122,38 @@ export function cssPlugin(config: ResolvedConfig): Plugin { return } - const urlReplacer: CssUrlReplacer = server - ? (url, importer) => { - if (url.startsWith('/')) { - return config.base + url.slice(1) - } else { - const filePath = normalizePath( - path.resolve(path.dirname(importer || id), url) - ) - return fileToDevUrl(filePath, config) - } - } - : (url, importer) => { - return urlToBuiltUrl(url, importer || id, config, this) - } + const urlReplacer: CssUrlReplacer = async (url, importer) => { + if (checkPublicFile(url, config)) { + return config.base + url.slice(1) + } + const resolved = await resolveUrl(url, importer) + if (resolved) { + return fileToUrl(resolved, config, this) + } + return url + } + + // const urlReplacer: CssUrlReplacer = server + // ? (url, importer) => { + // if (url.startsWith('/')) { + // return config.base + url.slice(1) + // } else { + // const filePath = normalizePath( + // path.resolve(path.dirname(importer || id), url) + // ) + // return fileToDevUrl(filePath, config) + // } + // } + // : (url, importer) => { + // return urlToBuiltUrl(url, importer || id, config, this) + // } const { code: css, modules, deps } = await compileCSS( id, raw, config, urlReplacer, - resolvers + atImportResolvers ) if (modules) { moduleCache.set(id, modules) @@ -416,13 +432,13 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { } } -interface CSSResolvers { +interface CSSAtImportResolvers { css: ResolveFn sass: ResolveFn less: ResolveFn } -function createCSSResolvers(config: ResolvedConfig): CSSResolvers { +function createCSSResolvers(config: ResolvedConfig): CSSAtImportResolvers { let cssResolve: ResolveFn | undefined let sassResolve: ResolveFn | undefined let lessResolve: ResolveFn | undefined @@ -471,7 +487,7 @@ async function compileCSS( code: string, config: ResolvedConfig, urlReplacer: CssUrlReplacer, - resolvers: CSSResolvers + atImportResolvers: CSSAtImportResolvers ): Promise<{ code: string map?: SourceMap @@ -530,7 +546,7 @@ async function compileCSS( code, config.root, opts, - resolvers + atImportResolvers ) if (preprocessResult.errors.length) { throw preprocessResult.errors[0] @@ -557,7 +573,10 @@ async function compileCSS( postcssPlugins.unshift( (await import('postcss-import')).default({ async resolve(id, basedir) { - const resolved = await resolvers.css(id, path.join(basedir, '*')) + const resolved = await atImportResolvers.css( + id, + path.join(basedir, '*') + ) if (resolved) { return path.resolve(resolved) } @@ -799,7 +818,7 @@ type StylePreprocessor = ( additionalData?: PreprocessorAdditionalData filename: string }, - resolvers: CSSResolvers + resolvers: CSSAtImportResolvers ) => StylePreprocessorResults | Promise export interface StylePreprocessorResults { @@ -954,13 +973,13 @@ let ViteLessManager: any function createViteLessPlugin( less: typeof Less, rootFile: string, - resolvers: CSSResolvers + resolvers: CSSAtImportResolvers ): Less.Plugin { if (!ViteLessManager) { ViteLessManager = class ViteManager extends less.FileManager { resolvers rootFile - constructor(rootFile: string, resolvers: CSSResolvers) { + constructor(rootFile: string, resolvers: CSSAtImportResolvers) { super() this.rootFile = rootFile this.resolvers = resolvers