Skip to content

Commit

Permalink
feat: resolve css relative urls + base64 inline
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed May 3, 2020
1 parent 756da62 commit f29037d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export async function build(options: BuildOptions = {}): Promise<BuildResult> {
__DEV__: 'false'
}),
// vite:css
createBuildCssPlugin(cssFileName, minify),
createBuildCssPlugin(assetsDir, cssFileName, minify),
// vite:asset
createBuildAssetPlugin(assetsDir),
// minify with terser
Expand Down
67 changes: 49 additions & 18 deletions src/node/buildPluginAsset.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,69 @@
import path from 'path'
import { promises as fs } from 'fs'
import { Plugin } from 'rollup'
import { Plugin, OutputBundle } from 'rollup'
import { isStaticAsset } from './utils'
import hash_sum from 'hash-sum'
import slash from 'slash'
import mime from 'mime-types'

const debug = require('debug')('vite:build:asset')

// TODO make this configurable
const inlineThreshold = 10000

export const getAssetPublicPath = async (id: string, assetsDir: string) => {
const ext = path.extname(id)
const baseName = path.basename(id, ext)
const resolvedFileName = `${baseName}.${hash_sum(id)}${ext}`

let url = slash(path.join('/', assetsDir, resolvedFileName))
const content = await fs.readFile(id)
if (!id.endsWith(`.svg`)) {
if (content.length < inlineThreshold) {
url = `data:${mime.lookup(id)};base64,${content.toString('base64')}`
}
}

return {
content,
fileName: resolvedFileName,
url
}
}

export const registerAssets = (
assets: Map<string, string>,
bundle: OutputBundle
) => {
for (const [fileName, source] of assets) {
bundle[fileName] = {
isAsset: true,
type: 'asset',
fileName,
source
}
}
}

export const createBuildAssetPlugin = (assetsDir: string): Plugin => {
const assets = new Map()

return {
name: 'vite:asset',
load(id) {
async load(id) {
if (isStaticAsset(id)) {
const ext = path.extname(id)
const baseName = path.basename(id, ext)
const resolvedName = `${baseName}.${hash_sum(id)}${ext}`
assets.set(id, resolvedName)
const publicPath = slash(path.join('/', assetsDir, resolvedName))
debug(`${id} -> ${publicPath}`)
return `export default ${JSON.stringify(publicPath)}`
const { fileName, content, url } = await getAssetPublicPath(
id,
assetsDir
)
assets.set(fileName, content)
debug(`${id} -> ${url}`)
return `export default ${JSON.stringify(url)}`
}
},

async generateBundle(_options, bundle) {
for (const [from, fileName] of assets) {
bundle[fileName] = {
isAsset: true,
type: 'asset',
fileName,
source: await fs.readFile(from)
}
}
generateBundle(_options, bundle) {
registerAssets(assets, bundle)
}
}
}
35 changes: 34 additions & 1 deletion src/node/buildPluginCss.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,46 @@
import path from 'path'
import { Plugin } from 'rollup'
import { getAssetPublicPath, registerAssets } from './buildPluginAsset'

const debug = require('debug')('vite:css')

const urlRE = /(url\(\s*['"]?)([^"')]+)(["']?\s*\))/g

export const createBuildCssPlugin = (
assetsDir: string,
cssFileName: string,
minify: boolean
): Plugin => {
const styles: Map<string, string> = new Map()
const assets = new Map()

return {
name: 'vite:css',
transform(code: string, id: string) {
async transform(code: string, id: string) {
if (id.endsWith('.css')) {
// process url() - register referenced files as assets
// and rewrite the url to the resolved public path
if (urlRE.test(code)) {
const fileDir = path.dirname(id)
urlRE.lastIndex = 0
let match
let remaining = code
let rewritten = ''
while ((match = urlRE.exec(remaining))) {
rewritten += remaining.slice(0, match.index)
const [matched, before, rawUrl, after] = match
const file = path.resolve(fileDir, rawUrl)
const { fileName, content, url } = await getAssetPublicPath(
file,
assetsDir
)
assets.set(fileName, content)
debug(`url(${rawUrl}) -> url(${url})`)
rewritten += `${before}${url}${after}`
remaining = remaining.slice(match.index + matched.length)
}
code = rewritten + remaining
}
styles.set(id, code)
return '/* css extracted by vite */'
}
Expand All @@ -36,6 +67,8 @@ export const createBuildCssPlugin = (
fileName: cssFileName,
source: css
}

registerAssets(assets, bundle)
}
}
}

0 comments on commit f29037d

Please sign in to comment.