build: add browser builds for @vue/compiler-sfc
This commit is contained in:
@@ -31,7 +31,6 @@ import {
|
||||
advancePositionWithMutation,
|
||||
assert,
|
||||
isSimpleIdentifier,
|
||||
loadDep,
|
||||
toValidAssetId
|
||||
} from './utils'
|
||||
import { isString, isArray, isSymbol } from '@vue/shared'
|
||||
@@ -167,7 +166,7 @@ function createCodegenContext(
|
||||
|
||||
if (!__BROWSER__ && sourceMap) {
|
||||
// lazy require source-map implementation, only in non-browser builds
|
||||
context.map = new (loadDep('source-map')).SourceMapGenerator()
|
||||
context.map = new SourceMapGenerator()
|
||||
context.map!.setSourceContent(filename, context.source)
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ import {
|
||||
KEEP_ALIVE,
|
||||
BASE_TRANSITION
|
||||
} from './runtimeHelpers'
|
||||
import { isString, isFunction, isObject, hyphenate } from '@vue/shared'
|
||||
import { isString, isObject, hyphenate } from '@vue/shared'
|
||||
import { parse } from '@babel/parser'
|
||||
import { walk } from 'estree-walker'
|
||||
import { Node } from '@babel/types'
|
||||
|
||||
export const isBuiltInType = (tag: string, expected: string): boolean =>
|
||||
@@ -49,31 +50,16 @@ export function isCoreComponent(tag: string): symbol | void {
|
||||
}
|
||||
}
|
||||
|
||||
// cache node requires
|
||||
// lazy require dependencies so that they don't end up in rollup's dep graph
|
||||
// and thus can be tree-shaken in browser builds.
|
||||
let _parse: typeof parse
|
||||
let _walk: any
|
||||
|
||||
export function loadDep(name: string) {
|
||||
if (!__BROWSER__ && typeof process !== 'undefined' && isFunction(require)) {
|
||||
return require(name)
|
||||
} else {
|
||||
// This is only used when we are building a dev-only build of the compiler
|
||||
// which runs in the browser but also uses Node deps.
|
||||
return (window as any)._deps[name]
|
||||
}
|
||||
}
|
||||
|
||||
export const parseJS: typeof parse = (code, options) => {
|
||||
assert(
|
||||
!__BROWSER__,
|
||||
`Expression AST analysis can only be performed in non-browser builds.`
|
||||
)
|
||||
if (!_parse) {
|
||||
_parse = loadDep('@babel/parser').parse
|
||||
if (__BROWSER__) {
|
||||
assert(
|
||||
!__BROWSER__,
|
||||
`Expression AST analysis can only be performed in non-browser builds.`
|
||||
)
|
||||
return null as any
|
||||
} else {
|
||||
return parse(code, options)
|
||||
}
|
||||
return _parse(code, options)
|
||||
}
|
||||
|
||||
interface Walker {
|
||||
@@ -82,12 +68,15 @@ interface Walker {
|
||||
}
|
||||
|
||||
export const walkJS = (ast: Node, walker: Walker) => {
|
||||
assert(
|
||||
!__BROWSER__,
|
||||
`Expression AST analysis can only be performed in non-browser builds.`
|
||||
)
|
||||
const walk = _walk || (_walk = loadDep('estree-walker').walk)
|
||||
return walk(ast, walker)
|
||||
if (__BROWSER__) {
|
||||
assert(
|
||||
!__BROWSER__,
|
||||
`Expression AST analysis can only be performed in non-browser builds.`
|
||||
)
|
||||
return null as any
|
||||
} else {
|
||||
return (walk as any)(ast, walker)
|
||||
}
|
||||
}
|
||||
|
||||
const nonIdentifierRE = /^\d|[^\$\w]/
|
||||
|
||||
@@ -6,6 +6,10 @@ This package contains lower level utilities that you can use if you are writing
|
||||
|
||||
The API surface is intentionally minimal - the goal is to reuse as much as possible while being as flexible as possible.
|
||||
|
||||
## Browser Build Usage
|
||||
|
||||
This package relies on `postcss`, `postcss-selector-parser` and `postcss-modules`
|
||||
|
||||
## API
|
||||
|
||||
TODO
|
||||
|
||||
@@ -8,10 +8,14 @@
|
||||
"dist"
|
||||
],
|
||||
"buildOptions": {
|
||||
"prod": false,
|
||||
"name": "VueCompilerSFC",
|
||||
"formats": [
|
||||
"cjs"
|
||||
]
|
||||
"cjs",
|
||||
"global",
|
||||
"esm-browser"
|
||||
],
|
||||
"prod": false,
|
||||
"enableNonBrowserBranches": true
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -94,20 +94,24 @@ export function doCompileStyle(
|
||||
}
|
||||
let cssModules: Record<string, string> | undefined
|
||||
if (modules) {
|
||||
if (options.isAsync) {
|
||||
plugins.push(
|
||||
require('postcss-modules')({
|
||||
...modulesOptions,
|
||||
getJSON: (cssFileName: string, json: Record<string, string>) => {
|
||||
cssModules = json
|
||||
}
|
||||
})
|
||||
)
|
||||
} else {
|
||||
if (__GLOBAL__ || __ESM_BROWSER__) {
|
||||
throw new Error(
|
||||
'`modules` option can only be used with compileStyleAsync().'
|
||||
'[@vue/compiler-sfc] `modules` option is not supported in the browser build.'
|
||||
)
|
||||
}
|
||||
if (!options.isAsync) {
|
||||
throw new Error(
|
||||
'[@vue/compiler-sfc] `modules` option can only be used with compileStyleAsync().'
|
||||
)
|
||||
}
|
||||
plugins.push(
|
||||
require('postcss-modules')({
|
||||
...modulesOptions,
|
||||
getJSON: (_cssFileName: string, json: Record<string, string>) => {
|
||||
cssModules = json
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const postCSSOptions: ProcessOptions = {
|
||||
@@ -172,6 +176,14 @@ function preprocess(
|
||||
options: SFCStyleCompileOptions,
|
||||
preprocessor: StylePreprocessor
|
||||
): StylePreprocessorResults {
|
||||
if ((__ESM_BROWSER__ || __GLOBAL__) && !options.preprocessCustomRequire) {
|
||||
throw new Error(
|
||||
`[@vue/compiler-sfc] Style preprocessing in the browser build must ` +
|
||||
`provide the \`preprocessCustomRequire\` option to return the in-browser ` +
|
||||
`version of the preprocessor.`
|
||||
)
|
||||
}
|
||||
|
||||
return preprocessor.render(
|
||||
options.source,
|
||||
options.map,
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
} from './templateTransformAssetUrl'
|
||||
import { transformSrcset } from './templateTransformSrcset'
|
||||
import { isObject } from '@vue/shared'
|
||||
import * as CompilerDOM from '@vue/compiler-dom'
|
||||
import * as CompilerSSR from '@vue/compiler-ssr'
|
||||
import consolidate from 'consolidate'
|
||||
|
||||
export interface TemplateCompiler {
|
||||
@@ -38,6 +40,7 @@ export interface SFCTemplateCompileOptions {
|
||||
compilerOptions?: CompilerOptions
|
||||
preprocessLang?: string
|
||||
preprocessOptions?: any
|
||||
preprocessCustomRequire?: (id: string) => any
|
||||
transformAssetUrls?: AssetURLOptions | boolean
|
||||
}
|
||||
|
||||
@@ -66,9 +69,25 @@ function preprocess(
|
||||
export function compileTemplate(
|
||||
options: SFCTemplateCompileOptions
|
||||
): SFCTemplateCompileResults {
|
||||
const { preprocessLang } = options
|
||||
const preprocessor =
|
||||
preprocessLang && consolidate[preprocessLang as keyof typeof consolidate]
|
||||
const { preprocessLang, preprocessCustomRequire } = options
|
||||
|
||||
if (
|
||||
(__ESM_BROWSER__ || __GLOBAL__) &&
|
||||
preprocessLang &&
|
||||
!preprocessCustomRequire
|
||||
) {
|
||||
throw new Error(
|
||||
`[@vue/compiler-sfc] Template preprocessing in the browser build must ` +
|
||||
`provide the \`preprocessCustomRequire\` option to return the in-browser ` +
|
||||
`version of the preprocessor in the shape of { render(): string }.`
|
||||
)
|
||||
}
|
||||
|
||||
const preprocessor = preprocessLang
|
||||
? preprocessCustomRequire
|
||||
? preprocessCustomRequire(preprocessLang)
|
||||
: require('consolidate')[preprocessLang as keyof typeof consolidate]
|
||||
: false
|
||||
if (preprocessor) {
|
||||
try {
|
||||
return doCompileTemplate({
|
||||
@@ -108,7 +127,7 @@ function doCompileTemplate({
|
||||
inMap,
|
||||
source,
|
||||
ssr = false,
|
||||
compiler = ssr ? require('@vue/compiler-ssr') : require('@vue/compiler-dom'),
|
||||
compiler = ssr ? (CompilerSSR as TemplateCompiler) : CompilerDOM,
|
||||
compilerOptions = {},
|
||||
transformAssetUrls
|
||||
}: SFCTemplateCompileOptions): SFCTemplateCompileResults {
|
||||
|
||||
@@ -6,9 +6,9 @@ import {
|
||||
TextModes
|
||||
} from '@vue/compiler-core'
|
||||
import { RawSourceMap, SourceMapGenerator } from 'source-map'
|
||||
import LRUCache from 'lru-cache'
|
||||
import { generateCodeFrame } from '@vue/shared'
|
||||
import { TemplateCompiler } from './compileTemplate'
|
||||
import * as CompilerDOM from '@vue/compiler-dom'
|
||||
|
||||
export interface SFCParseOptions {
|
||||
filename?: string
|
||||
@@ -57,7 +57,13 @@ export interface SFCParseResult {
|
||||
}
|
||||
|
||||
const SFC_CACHE_MAX_SIZE = 500
|
||||
const sourceToSFC = new LRUCache<string, SFCParseResult>(SFC_CACHE_MAX_SIZE)
|
||||
const sourceToSFC =
|
||||
__GLOBAL__ || __ESM_BROWSER__
|
||||
? new Map<string, SFCParseResult>()
|
||||
: (new (require('lru-cache'))(SFC_CACHE_MAX_SIZE) as Map<
|
||||
string,
|
||||
SFCParseResult
|
||||
>)
|
||||
|
||||
export function parse(
|
||||
source: string,
|
||||
@@ -66,7 +72,7 @@ export function parse(
|
||||
filename = 'component.vue',
|
||||
sourceRoot = '',
|
||||
pad = false,
|
||||
compiler = require('@vue/compiler-dom')
|
||||
compiler = CompilerDOM
|
||||
}: SFCParseOptions = {}
|
||||
): SFCParseResult {
|
||||
const sourceKey =
|
||||
|
||||
@@ -6,15 +6,8 @@
|
||||
<div id="source" class="editor"></div>
|
||||
<div id="output" class="editor"></div>
|
||||
|
||||
<script src="https://unpkg.com/estree-walker@0.8.1/dist/estree-walker.umd.js"></script>
|
||||
<script src="https://unpkg.com/source-map@0.6.1/dist/source-map.js"></script>
|
||||
<script src="https://unpkg.com/monaco-editor@0.20.0/min/vs/loader.js"></script>
|
||||
<script>
|
||||
window._deps = {
|
||||
'estree-walker': estreeWalker,
|
||||
'source-map': sourceMap
|
||||
}
|
||||
|
||||
require.config({
|
||||
paths: {
|
||||
'vs': 'https://unpkg.com/monaco-editor@0.20.0/min/vs'
|
||||
|
||||
@@ -6,16 +6,8 @@
|
||||
<div id="source" class="editor"></div>
|
||||
<div id="output" class="editor"></div>
|
||||
|
||||
<script src="../../node_modules/estree-walker/dist/estree-walker.umd.js"></script>
|
||||
<script src="../../node_modules/source-map/dist/source-map.js"></script>
|
||||
<script src="../../node_modules/monaco-editor/min/vs/loader.js"></script>
|
||||
<script>
|
||||
window._deps = {
|
||||
// @babel/parser is injected by the bundle
|
||||
'estree-walker': estreeWalker,
|
||||
'source-map': sourceMap
|
||||
}
|
||||
|
||||
require.config({
|
||||
paths: {
|
||||
'vs': '../../node_modules/monaco-editor/min/vs'
|
||||
|
||||
@@ -4,9 +4,6 @@ import { compile as ssrCompile } from '@vue/compiler-ssr'
|
||||
import { compilerOptions, initOptions, ssrMode } from './options'
|
||||
import { watchEffect } from '@vue/runtime-dom'
|
||||
import { SourceMapConsumer } from 'source-map'
|
||||
import { parse } from '@babel/parser'
|
||||
|
||||
window._deps['@babel/parser'] = { parse }
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -57,7 +54,7 @@ window.init = () => {
|
||||
)
|
||||
console.log(`AST: `, ast)
|
||||
lastSuccessfulCode = code + `\n\n// Check the console for the AST`
|
||||
lastSuccessfulMap = new window._deps['source-map'].SourceMapConsumer(map)
|
||||
lastSuccessfulMap = new SourceMapConsumer(map!)
|
||||
lastSuccessfulMap!.computeColumnSpans()
|
||||
} catch (e) {
|
||||
lastSuccessfulCode = `/* ERROR: ${
|
||||
|
||||
Reference in New Issue
Block a user