From ab13f3b6ff7499831ec7cb890ff128741cdcc871 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Thu, 21 Nov 2019 14:08:03 +0800 Subject: [PATCH] fix: call transformer from whitelisted custom blocks (#310) --- package.json | 2 +- src/index.ts | 47 ++++++++++------- src/utils.ts | 30 +++++------ .../__snapshots__/custom-blocks.spec.ts.snap | 52 +++++++++++++++++++ test/options/custom-blocks.spec.ts | 36 ++++++++++--- yarn.lock | 8 +-- 6 files changed, 130 insertions(+), 45 deletions(-) create mode 100644 test/options/__snapshots__/custom-blocks.spec.ts.snap diff --git a/package.json b/package.json index 7225120..958d947 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "runtime/" ], "dependencies": { - "@vue/component-compiler": "^4.1.0", + "@vue/component-compiler": "^4.2.0", "@vue/component-compiler-utils": "^3.0.0", "debug": "^4.1.1", "hash-sum": "^1.0.2", diff --git a/src/index.ts b/src/index.ts index 7cce438..22b9bc7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,8 @@ import { parseVuePartRequest, resolveVuePart, isVuePartRequest, - transformRequireToImport + transformRequireToImport, + DEFAULT_LANGS } from './utils' import { createDefaultCompiler, @@ -183,11 +184,15 @@ export default function vue(opts: Partial = {}): Plugin { if (!opts.styleInjectorShadow) opts.styleInjectorShadow = '~' + require.resolve('../runtime/shadow') - createVuePartRequest.defaultLang = { - ...createVuePartRequest.defaultLang, + const defaultLang: Record = { + ...DEFAULT_LANGS, ...opts.defaultLang } + if (opts.defaultLang && typeof opts.defaultLang.styles === 'string') { + defaultLang.style = opts.defaultLang.styles + } + const shouldExtractCss = opts.css === false const customBlocks: string[] = [] @@ -269,10 +274,10 @@ export default function vue(opts: Partial = {}): Plugin { resolveId(id, importer) { const request = id - - if (!importer) return + + if (!importer) return if (!isVuePartRequest(id)) return - + id = path.resolve(path.dirname(importer), id) const ref = parseVuePartRequest(id) @@ -307,7 +312,12 @@ export default function vue(opts: Partial = {}): Plugin { let map = element.map as any if (request.meta.type === 'styles') { - code = prependStyle(id, request.meta.lang, code, map).code + code = prependStyle( + id, + request.meta.lang || defaultLang.style, + code, + map + ).code } dL(`id: ${id}\ncode: \n${code}\nmap: ${JSON.stringify(map, null, 2)}\n\n`) @@ -344,7 +354,7 @@ export default function vue(opts: Partial = {}): Plugin { if (style.content) { style.content = prependStyle( filename, - style.lang || 'css', + style.lang || defaultLang.style, style.content, style.map ).code @@ -388,12 +398,12 @@ export default function vue(opts: Partial = {}): Plugin { code: ` export * from '${createVuePartRequest( filename, - descriptor.script.lang || 'js', + descriptor.script.lang || defaultLang.script, 'script' )}' import script from '${createVuePartRequest( filename, - descriptor.script.lang || 'js', + descriptor.script.lang || defaultLang.script, 'script' )}' export default script @@ -433,22 +443,23 @@ export default function vue(opts: Partial = {}): Plugin { .filter(Boolean) } + // Why? input.script.code = input.script.code.replace(/^\s+/gm, '') const result = assemble(compiler, filename, beforeAssemble(input), opts) descriptor.customBlocks.forEach((block, index) => { if (!isAllowed(block.type)) return + const lang = + typeof block.attrs.lang === 'string' + ? block.attrs.lang + : defaultLang[block.type] || block.type + const id = createVuePartRequest(filename, lang, block.type, index) result.code += '\n' + - `export * from '${createVuePartRequest( - filename, - (typeof block.attrs.lang === 'string' && block.attrs.lang) || - createVuePartRequest.defaultLang[block.type] || - block.type, - 'customBlocks', - index - )}'` + `export * from '${id}'\n` + + `import __custom_block_${index}__ from '${id}'\n` + + `__custom_block_${index}__(__vue_component__)` }) dT( diff --git a/src/utils.ts b/src/utils.ts index 82bd16d..ac1afb7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -21,14 +21,6 @@ export interface VuePartRequestMeta { index?: number } -export interface VuePartRequestCreator { - (filename: string, lang: string, type: string, index?: number): string - - defaultLang: { - [key: string]: string - } -} - export function createVueFilter( include: Array | string | RegExp = [/\.vue$/i], exclude: Array | string | RegExp = [] @@ -49,7 +41,11 @@ export function getVueMetaFromQuery(id: string): VuePartRequestMeta | null { ? (query[PARAM_NAME] as any)[0] : query[PARAM_NAME]) as string - const [type, index, lang] = data.split('.') + let [type, index, lang] = data.split('.') + + if (!/^(template|styles|script)$/i.test(type)) { + type = 'customBlocks' + } return (lang ? { type, lang, index: parseInt(index) } // styles.0.css @@ -64,13 +60,13 @@ export function isVuePartRequest(id: string): boolean { return getVueMetaFromQuery(id) !== null } -export const createVuePartRequest: VuePartRequestCreator = (( +export function createVuePartRequest( filename: string, lang: string | undefined, type: string, index?: number -): string => { - lang = lang || createVuePartRequest.defaultLang[type] +): string { + lang = DEFAULT_LANGS[type] || lang const match = GET_QUERY.exec(filename) @@ -81,12 +77,14 @@ export const createVuePartRequest: VuePartRequestCreator = (( .join('.') return `${path.basename(filename)}?${queryString.stringify(query)}` -}) as VuePartRequestCreator +} -createVuePartRequest.defaultLang = { +export const DEFAULT_LANGS: Record = { template: 'html', - styles: 'css', - script: 'js' + style: 'css', + script: 'js', + docs: 'md', + i18n: 'json' } export function parseVuePartRequest(id: string): VuePartRequest | undefined { diff --git a/test/options/__snapshots__/custom-blocks.spec.ts.snap b/test/options/__snapshots__/custom-blocks.spec.ts.snap new file mode 100644 index 0000000..70d3ef3 --- /dev/null +++ b/test/options/__snapshots__/custom-blocks.spec.ts.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`customBlocks transform 1`] = ` +"var __custom_block_1__ = \\"// My Docs Block\\"; + +/* script */ + +/* template */ +var __vue_render__ = function() { + var _vm = this; + var _h = _vm.$createElement; + var _c = _vm._self._c || _h; + return _c(\\"div\\", [_vm._v(\\"Hello, world\\")]) +}; +var __vue_staticRenderFns__ = []; +__vue_render__._withStripped = true; + + /* style */ + const __vue_inject_styles__ = undefined; + /* scoped */ + const __vue_scope_id__ = undefined; + /* module identifier */ + const __vue_module_identifier__ = undefined; + /* functional template */ + const __vue_is_functional_template__ = false; + /* component normalizer */ + const __vue_normalize__ = vue-runtime-helpers/dist/normalize-component.mjs; + /* style inject */ + + /* style inject SSR */ + + /* style inject shadow dom */ + + + + const __vue_component__ = __vue_normalize__( + { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, + __vue_inject_styles__, + {}, + __vue_scope_id__, + __vue_is_functional_template__, + __vue_module_identifier__, + false, + undefined, + undefined, + undefined + ); +__custom_block_1__(__vue_component__); + +export default __vue_component__; +" +`; diff --git a/test/options/custom-blocks.spec.ts b/test/options/custom-blocks.spec.ts index 5abf48b..c13acaa 100644 --- a/test/options/custom-blocks.spec.ts +++ b/test/options/custom-blocks.spec.ts @@ -1,6 +1,16 @@ import vue, { VuePluginOptions } from '../../src' import { pluginInline } from '../setup/plugins' import { rollup } from 'rollup' +function pluginText() { + return { + name: 'text', + transform(source: string, id: string) { + if (/\.(md|txt)$/.test(id)) { + return `export default ${JSON.stringify(source.trim())}` + } + }, + } +} describe('customBlocks', () => { async function setup(options?: Partial) { @@ -21,11 +31,16 @@ describe('customBlocks', () => { ` ), + pluginText(), vue({ ...options, - normalizer: 'vue-runtime-helpers/dist/normalize-component.mjs' - }) - ] + defaultLang: { + docs: 'md', + custom: 'txt', + }, + normalizer: 'vue-runtime-helpers/dist/normalize-component.mjs', + }), + ], }) .then(bundle => bundle.generate({ format: 'es' })) .then(generated => generated.output[0]) @@ -40,7 +55,7 @@ describe('customBlocks', () => { it('array of tags', async () => { const { code } = await setup({ - customBlocks: ['custom'] + customBlocks: ['custom'], }) expect(code).toEqual(expect.stringContaining('My Custom Block')) @@ -48,7 +63,7 @@ describe('customBlocks', () => { }) it('negative array of tags', async () => { const { code } = await setup({ - customBlocks: ['*', '!custom'] + customBlocks: ['*', '!custom'], }) expect(code).not.toEqual(expect.stringContaining('My Custom Block')) @@ -58,10 +73,19 @@ describe('customBlocks', () => { const { code } = await setup({ customBlocks(tag) { return tag === 'custom' - } + }, }) expect(code).toEqual(expect.stringContaining('My Custom Block')) expect(code).not.toEqual(expect.stringContaining('My Docs Block')) }) + + it('transform', async () => { + const { code } = await setup({ + customBlocks: ['docs'], + }) + + expect(code).toEqual(expect.stringContaining('__custom_block_1__(__vue_component__)')) + expect(code).toMatchSnapshot() + }) }) diff --git a/yarn.lock b/yarn.lock index 2411899..abe64c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1571,10 +1571,10 @@ source-map "~0.6.1" vue-template-es2015-compiler "^1.9.0" -"@vue/component-compiler@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@vue/component-compiler/-/component-compiler-4.1.0.tgz#92ccb90e425aa7e61d58bf092a5cfcdd6d0f9315" - integrity sha512-20S7mm7CYP94m2Morw2ftz1tqoBu1nX7KYiqo5rlgKPZ0dlY7VZX7wAL/etN3s4HD0PBeenr1pUUCBIgGSaB2g== +"@vue/component-compiler@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@vue/component-compiler/-/component-compiler-4.2.0.tgz#437855cd59f3d713a4eef81bac7ab0f4950977b4" + integrity sha512-bxFNxUpKzLfHDoGTsAe2w7gEz4OwII7tp5m7sAXES1DApbpYglH4YSpYxdZRZ4GN/wj2fPD0u72QRJXd4UPvFQ== dependencies: "@vue/component-compiler-utils" "^3.0.0" clean-css "^4.1.11"