diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..7b9c239 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,154 @@ +declare module VueComponentCompiler { + /** + * Parse SFC file into block descriptors. + * + * @param content Contents of the SFC. + * @param filename Filepath (used for cache key & in generated source maps) + */ + export function parse(content: string, filename: string, config: ParserConfig): SFCDescriptor + + /** + * Compile styles for SFC + * + * @param styles List of styles to process. + * @param filename SFC file path + */ + export function compileStyles(styles: Array, filename: string, config: StyleCompilerConfig): Promise> + + /** + * Compile template to render functions + * + * @param template Template to compile + * @param filename SFC file path + */ + export function compileTemplate(template: TemplateCompilerSource, filename: string, config: TemplateCompilerConfig): Promise + + export function assemble(source: AssemblerSource, filename: string, config: AssemblerConfig): string + + type ParserConfig = { + needMap: boolean + } + + type SFCDescriptor = { + script: ScriptDescriptor + styles: Array + template: TemplateDescriptor + customBlocks: Array + } + + type BlockDescriptor = { + type: string // tag + content: string + start: number + end: number + attrs: Array<{ name: string, value: string | boolean}> + } + + type StyleDescriptor = BlockDescriptor & { + scoped?: boolean + module?: string | boolean + lang?: string + src?: string + } + + type ScriptDescriptor = BlockDescriptor & { + lang?: string + src?: string + } + + type TemplateDescriptor = BlockDescriptor & { + lang?: string + src?: string + } + + type CompilerSource = { + code: string + map?: object // prev source map + } + + type StyleCompilerSource = CompilerSource & { + descriptor: StyleDescriptor + } + + type StyleCompilerConfig = { + scopeId: string // used for scoped styles. + needMap?: boolean + plugins?: Array // postcss plugins + options?: object // postcss options + onWarn?: MessageHandler + } + + type MessageHandler = (message: Message) => void + + type Message = { + type: string + text?: string + } + + type CompilerOutput = { + code: string, + map?: object + } + + type StyleCompilerOutput = CompilerOutput & {} + + type TemplateCompilerSource = CompilerSource & { + descriptor: TemplateDescriptor + } + + type TemplateCompilerConfig = { + isHot?: boolean // false + isServer?: boolean // false + isProduction?: boolean // true + optimizeSSR?: boolean // true + buble: object // see https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js#L6 + options?: { + preserveWhitspace?: boolean // true + } + transformToRequire?: object + plugins?: Array + } + + type TemplateCompilerOutput = CompilerOutput & { + errors: Array + tips: Array + } + + type AssemblerSource = { + script: { + id: string, + descriptor: ScriptDescriptor + } + styles: Array<{ + id: string + hotPath: string + descriptor: StyleDescriptor + }> + render: { + id: string + descriptor: TemplateDescriptor + } + customBlocks: Array<{ + id: string + descriptor: BlockDescriptor + }> + } + + type AssemblerConfig = { + hashKey?: string + esModule?: boolean // true + shortFilePath?: string // = filename + require?: { + vueHotReloadAPI?: string // vue-hot-reload-api + normalizeComponent?: string // vue-component-compiler/src/normalize-component.js + } + moduleId: string // same as scopeId of style compiler. + moduleIdentifier?: string // autogenerated + isHot?: boolean // false + isServer?: boolean // false + isProduction?: boolean // true + isInjectable?: boolean // false + hasStyleInjectFn?: boolean // false + onWarn?: MessageHandler // console.warn + } +} diff --git a/src/assemble.js b/src/assemble.js index dbf193d..4805e76 100644 --- a/src/assemble.js +++ b/src/assemble.js @@ -1,27 +1,12 @@ -const defaultsDeep = require('lodash.defaultsdeep') +const defaults = require('lodash.defaultsdeep') +const hash = require('hash-sum') + +const genId = require('./gen-id') const DISPOSED = 'disposed' const INJECT_STYLE_FN = 'injectStyle' const CSS_MODULES = 'cssModules' -const defaultConfig = { - esModule: true, - filename: null, - shortFilePath: null, - require: { - vueHotReloadAPI: 'vue-hot-reload-api', - normalizeComponent: 'vue-component-compiler/src/normalize-component.js' - }, - moduleId: null, // css scope id. - moduleIdentifier: null, // require for server. - isHot: false, - isServer: false, - isProduction: true, - isInjectable: false, - hasStyleInjectFn: false, - onWarn () {} -} - function _s (any) { return JSON.stringify(any) } @@ -41,13 +26,29 @@ function __vue_type__ (type, id, esModule, addPrefix = true) { return output } -module.exports = function assemble (script, render, styles, customBlocks, config) { +module.exports = function assemble (source, filename, config) { + config = defaults(config, { + esModule: true, + shortFilePath: filename, + require: { + vueHotReloadAPI: 'vue-hot-reload-api', + normalizeComponent: 'vue-component-compiler/src/normalize-component.js' + }, + moduleId: null, + moduleIdentifier: config.moduleIdentifier || hash(_s({ filename, config })), // require for server. TODO: verify this is correct. + isHot: false, + isServer: false, + isProduction: true, + isInjectable: false, + hasStyleInjectFn: false, + onWarn: message => console.warn(message) + }) + let output = '' + const { script, render, styles, customBlocks } = source const needsHotReload = !config.isProduction && config.isHot const hasScoped = styles.some(style => style.descriptor.scoped) - config = defaultsDeep({}, config, defaultConfig) - if (config.isInjectable) config.esModule = false if (needsHotReload) output += `var ${DISPOSED} = false\n` @@ -96,7 +97,7 @@ module.exports = function assemble (script, render, styles, customBlocks, config ` var oldLocals = ${CSS_MODULES}[${MODULE_KEY}]\n` + ` if (!oldLocals) return\n` + // 2. re-import (side effect: updates the