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(dev): support css sourcemap #659

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"chalk": "^4.0.0",
"chokidar": "^3.3.1",
"clean-css": "^4.2.3",
"concat-with-sourcemaps": "^1.1.0",
"debug": "^4.1.1",
"dotenv": "^8.2.0",
"dotenv-expand": "^5.1.0",
Expand Down Expand Up @@ -96,6 +97,7 @@
"rollup-pluginutils": "^2.8.2",
"selfsigned": "^1.10.7",
"slash": "^3.0.0",
"source-map": "^0.7.3",
"vue": "^3.0.0-rc.5",
"ws": "^7.2.3"
},
Expand Down
23 changes: 7 additions & 16 deletions src/node/server/serverPluginCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import {
getCssImportBoundaries,
recordCssImportChain,
rewriteCssUrls,
isCSSRequest
isCSSRequest,
ProcessedCSS
} from '../utils/cssUtils'
import qs from 'querystring'
import chalk from 'chalk'
import { InternalResolver } from '../resolver'
import { clientPublicPath } from './serverPluginClient'

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

export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
Expand All @@ -30,11 +30,12 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
) {
const id = JSON.stringify(hash_sum(ctx.path))
if (isImportRequest(ctx)) {
const { css, modules } = await processCss(root, ctx)
const { css, modules, map } = await processCss(root, ctx)
ctx.type = 'js'
// we rewrite css with `?import` to a js module that inserts a style
// tag linking to the actual raw url
ctx.body = codegenCss(id, css, modules)
ctx.map = map
}
}
})
Expand Down Expand Up @@ -119,11 +120,6 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
})
}

interface ProcessedCSS {
css: string
modules?: Record<string, string>
}

// processed CSS is cached in case the user ticks "disable cache" during dev
// which can lead to unnecessary processing on page reload
const processedCSS = new Map<string, ProcessedCSS>()
Expand All @@ -139,7 +135,7 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
const filePath = resolver.requestToFile(ctx.path)
const preprocessLang = ctx.path.replace(cssPreprocessLangRE, '$2')

const result = await compileCss(root, ctx.path, {
const result = await compileCss(root, ctx.path, ctx.read, {
id: '',
source: css,
filename: filePath,
Expand All @@ -150,12 +146,6 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {
modulesOptions: ctx.config.cssModuleOptions
})

if (typeof result === 'string') {
const res = { css: await rewriteCssUrls(css, ctx.path) }
processedCSS.set(ctx.path, res)
return res
}

recordCssImportChain(result.dependencies, filePath)

if (result.errors.length) {
Expand All @@ -165,7 +155,8 @@ export const cssPlugin: ServerPlugin = ({ root, app, watcher, resolver }) => {

const res = {
css: await rewriteCssUrls(result.code, ctx.path),
modules: result.modules
modules: result.modules,
map: result.map as any
}
processedCSS.set(ctx.path, res)
return res
Expand Down
7 changes: 5 additions & 2 deletions src/node/server/serverPluginVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,12 @@ export const vuePlugin: ServerPlugin = ({
index,
filePath,
publicPath,
ctx,
config
)
ctx.type = 'js'
ctx.body = codegenCss(`${id}-${index}`, result.code, result.modules)
ctx.map = result.map as any
return etagCacheCheck(ctx)
}

Expand Down Expand Up @@ -589,7 +591,7 @@ function compileSFCTemplate(

const result = {
code,
map: map as SourceMap
map: map as any
}

cached = cached || { styles: [], customs: [] }
Expand All @@ -606,6 +608,7 @@ async function compileSFCStyle(
index: number,
filePath: string,
publicPath: string,
ctx: Context,
{ cssPreprocessOptions, cssModuleOptions }: ServerPluginContext['config']
): Promise<SFCStyleCompileResults> {
let cached = vueCache.get(filePath)
Expand All @@ -619,7 +622,7 @@ async function compileSFCStyle(

const { generateCodeFrame } = resolveCompiler(root)
const resource = filePath + `?type=style&index=${index}`
const result = (await compileCss(root, publicPath, {
const result = (await compileCss(root, publicPath, ctx.read, {
source: style.content,
filename: resource,
id: ``, // will be computed in compileCss
Expand Down
48 changes: 43 additions & 5 deletions src/node/utils/cssUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {
SFCAsyncStyleCompileOptions,
SFCStyleCompileResults
} from '@vue/compiler-sfc'
import { getOriginalSourceMap } from './sourcemap'
import Concat from 'concat-with-sourcemaps'
import { SourceMap } from '../server/serverPluginSourceMap'

export const urlRE = /url\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/
export const cssPreprocessLangRE = /(.+)\.(less|sass|scss|styl|stylus|postcss)$/
Expand Down Expand Up @@ -51,9 +54,16 @@ export function rewriteCssUrls(
})
}

export interface ProcessedCSS {
css: string
modules?: Record<string, string>
map?: SourceMap
}

export async function compileCss(
root: string,
publicPath: string,
read: (filePath: string) => Promise<Buffer | string>,
{
source,
filename,
Expand All @@ -64,11 +74,16 @@ export async function compileCss(
preprocessOptions = {},
modulesOptions = {}
}: SFCAsyncStyleCompileOptions,
sourcemap: boolean = true,
isBuild: boolean = false
): Promise<SFCStyleCompileResults | string> {
): Promise<SFCStyleCompileResults> {
const id = hash_sum(publicPath)
const postcssConfig = await loadPostcssConfig(root)
const { compileStyleAsync } = resolveCompiler(root)
const map =
sourcemap && !filename.includes('.vue')
? (getOriginalSourceMap(source, filename) as any)
: null

if (
publicPath.endsWith('.css') &&
Expand All @@ -78,7 +93,13 @@ export async function compileCss(
!source.includes('@import')
) {
// no need to invoke compile for plain css if no postcss config is present
return source
return {
code: source,
map,
dependencies: new Set<string>(),
errors: [],
rawResult: undefined
}
}

const {
Expand Down Expand Up @@ -106,7 +127,7 @@ export async function compileCss(
}
}

return await compileStyleAsync({
const result = await compileStyleAsync({
source,
filename,
id: `data-v-${id}`,
Expand All @@ -118,14 +139,31 @@ export async function compileCss(
localsConvention: 'camelCase',
...modulesOptions
},

map,
preprocessLang,
preprocessCustomRequire: (id: string) => require(resolveFrom(root, id)),
preprocessOptions,

postcssOptions,
postcssPlugins
})

if (result.dependencies.size > 0 && sourcemap) {
const concat = new Concat(true, filename, '\n')
if (!filename.includes('.vue')) {
concat.add(filename, source, result.map)
}
for (const dependency of result.dependencies) {
const content = (await read(dependency)).toString()
concat.add(
dependency,
content,
getOriginalSourceMap(content, dependency) as any
)
}
result.map = JSON.parse(concat.sourceMap!)
}

return result
}

// postcss-load-config doesn't expose Result type
Expand Down
38 changes: 38 additions & 0 deletions src/node/utils/sourcemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { SourceNode, RawSourceMap } from 'source-map'

const SPLIT_REGEX = /(?!$)[^\n\r;{}]*[\n\r;{}]*/g

function splitCode(code: string) {
return code.match(SPLIT_REGEX) || []
}

export function getOriginalSourceMap(
code: string,
filePath: string
): RawSourceMap {
const lines = code.split('\n')

const linesSourceNode = lines.map((row, index) => {
let column = 0
const columnsSourceNode = splitCode(
row + (index !== lines.length - 1 ? '\n' : '')
).map((item) => {
if (/^\s*$/.test(item)) {
column += item.length
return item
}
const res = new SourceNode(index + 1, column, filePath, item)
column += item.length
return res
})
return new SourceNode(null, null, null, columnsSourceNode)
})

const sourceNode = new SourceNode(null, null, null, linesSourceNode)

const sourceMapGenerator = sourceNode.toStringWithSourceMap({
file: filePath
}).map
sourceMapGenerator.setSourceContent(filePath, code)
return sourceMapGenerator.toJSON()
}
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1764,6 +1764,13 @@ [email protected]:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=

concat-with-sourcemaps@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e"
integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==
dependencies:
source-map "^0.6.1"

consolidate@^0.15.1:
version "0.15.1"
resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7"
Expand Down