UNPKG

rollup-plugin-vue

Version:
265 lines (259 loc) 11.5 kB
'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var rollupPluginutils = require('rollup-pluginutils'); var queryString = require('querystring'); var path = require('path'); var componentCompiler = require('@vue/component-compiler'); var componentCompilerUtils = require('@vue/component-compiler-utils'); var debug = _interopDefault(require('debug')); const GET_QUERY = /\.vue(\.[a-z]+?)?\?(.+)$/i; const PARAM_NAME = 'rollup-plugin-vue'; function createVueFilter(include = [/\.vue$/i], exclude = []) { const filter = rollupPluginutils.createFilter(include, exclude); return id => filter(id); } function getVueMetaFromQuery(id) { const match = GET_QUERY.exec(id); if (match) { const query = queryString.parse(match[2]); if (PARAM_NAME in query) { const data = (Array.isArray(query[PARAM_NAME]) ? query[PARAM_NAME][0] : query[PARAM_NAME]); const [type, index, lang] = data.split('.'); return (lang ? { type, lang, index: parseInt(index) } // styles.0.css : { type, lang: index }); // script.js } } return null; } function isVuePartRequest(id) { return getVueMetaFromQuery(id) !== null; } const createVuePartRequest = ((filename, lang, type, index) => { lang = lang || createVuePartRequest.defaultLang[type]; const match = GET_QUERY.exec(filename); const query = match ? queryString.parse(match[2]) : {}; query[PARAM_NAME] = [type, index, lang] .filter(it => it !== undefined) .join('.'); return `${path.basename(filename)}?${queryString.stringify(query)}`; }); createVuePartRequest.defaultLang = { template: 'html', styles: 'css', script: 'js' }; function parseVuePartRequest(id) { if (!id.includes('.vue')) return; const filename = id.substr(0, id.lastIndexOf('.vue') + 4); const params = getVueMetaFromQuery(id); if (params === null) return; return { filename, meta: params }; } function resolveVuePart(descriptors, { filename, meta }) { const descriptor = descriptors.get(filename); if (!descriptor) throw Error('File not processed yet, ' + filename); const blocks = descriptor[meta.type]; const block = Array.isArray(blocks) ? blocks[meta.index] : blocks; if (!block) throw Error(`Requested (type=${meta.type} & index=${meta.index}) block not found in ${filename}`); return block; } function transformRequireToImport(code) { const imports = {}; let strImports = ''; code = code.replace(/require\(("(?:[^"\\]|\\.)+"|'(?:[^'\\]|\\.)+')\)/g, (_, name) => { if (!(name in imports)) { imports[name] = `__$_require_${name.replace(/[^a-z0-9]/g, '_').replace(/_{2,}/g, '_').replace(/^_|_$/g, '')}__`; strImports += 'import ' + imports[name] + ' from ' + name + '\n'; } return imports[name]; }); return strImports + code; } const templateCompiler = require('vue-template-compiler'); const hash = require('hash-sum'); const { version } = require('../package.json'); const d = debug('rollup-plugin-vue'); const dR = debug('rollup-plugin-vue:resolve'); const dL = debug('rollup-plugin-vue:load'); const dT = debug('rollup-plugin-vue:transform'); /** * Rollup plugin for handling .vue files. */ function vue(opts = {}) { const isVue = createVueFilter(opts.include, opts.exclude); const isProduction = process.env.NODE_ENV === 'production' || process.env.BUILD === 'production'; d('Version ' + version); d(`Build environment: ${isProduction ? 'production' : 'development'}`); d(`Build target: ${process.env.VUE_ENV || 'browser'}`); if (!opts.normalizer) opts.normalizer = '~' + 'vue-runtime-helpers/dist/normalize-component.js'; if (!opts.styleInjector) opts.styleInjector = '~' + 'vue-runtime-helpers/dist/inject-style/browser.js'; if (!opts.styleInjectorSSR) opts.styleInjectorSSR = '~' + 'vue-runtime-helpers/dist/inject-style/server.js'; createVuePartRequest.defaultLang = { ...createVuePartRequest.defaultLang, ...opts.defaultLang, }; const shouldExtractCss = opts.css === false; const blacklisted = new Set(opts.blackListCustomBlocks || ['*']); const whitelisted = new Set(opts.whiteListCustomBlocks || []); const isAllowed = (customBlockType) => (!blacklisted.has('*') || !blacklisted.has(customBlockType)) && (whitelisted.has('*') || whitelisted.has(customBlockType)); const beforeAssemble = opts.beforeAssemble || ((d) => d); delete opts.beforeAssemble; delete opts.css; delete opts.blackListCustomBlocks; delete opts.whiteListCustomBlocks; delete opts.defaultLang; delete opts.include; delete opts.exclude; opts.template = { transformAssetUrls: { video: ['src', 'poster'], source: 'src', img: 'src', image: 'xlink:href', }, ...opts.template, }; if (opts.template && typeof opts.template.isProduction === 'undefined') { opts.template.isProduction = isProduction; } const compiler = componentCompiler.createDefaultCompiler(opts); const descriptors = new Map(); if (opts.css === false) d('Running in CSS extract mode'); return { name: 'VuePlugin', resolveId(id, importer) { const request = id; if (id.startsWith('vue-runtime-helpers/')) { id = require.resolve(id); dR(`form: ${request} \nto: ${id}\n`); return id; } if (!isVuePartRequest(id)) return; id = path.resolve(path.dirname(importer), id); const ref = parseVuePartRequest(id); if (ref) { const element = resolveVuePart(descriptors, ref); const src = element.src; if (ref.meta.type !== 'styles' && typeof src === 'string') { if (src.startsWith('.')) { return path.resolve(path.dirname(ref.filename), src); } else { return require.resolve(src, { paths: [path.dirname(ref.filename)] }); } } dR(`from: ${request} \nto: ${id}\n`); return id; } }, load(id) { const request = parseVuePartRequest(id); if (!request) return null; const element = resolveVuePart(descriptors, request); const code = 'code' in element ? element.code // .code is set when extract styles is used. { css: false } : element.content; const map = element.map; dL(`id: ${id}\ncode: \n${code}\nmap: ${JSON.stringify(map, null, 2)}\n\n`); return { code, map }; }, async transform(source, filename) { if (isVue(filename)) { const descriptor = JSON.parse(JSON.stringify(componentCompilerUtils.parse({ filename, source, compiler: opts.compiler || templateCompiler, compilerParseOptions: opts.compilerParseOptions, sourceRoot: opts.sourceRoot, needMap: true, }))); const scopeId = 'data-v-' + (isProduction ? hash(path.basename(filename) + source) : hash(filename + source)); descriptors.set(filename, descriptor); const styles = await Promise.all(descriptor.styles.map(async (style) => { const compiled = await compiler.compileStyleAsync(filename, scopeId, style); if (compiled.errors.length > 0) throw Error(compiled.errors[0]); return compiled; })); const input = { scopeId, styles, customBlocks: [], }; if (descriptor.template) { input.template = compiler.compileTemplate(filename, descriptor.template); input.template.code = transformRequireToImport(input.template.code); if (input.template.errors && input.template.errors.length) { input.template.errors.map((error) => this.error(error)); } if (input.template.tips && input.template.tips.length) { input.template.tips.map((message) => this.warn({ message })); } } input.script = descriptor.script ? { code: ` export * from '${createVuePartRequest(filename, descriptor.script.lang || 'js', 'script')}' import script from '${createVuePartRequest(filename, descriptor.script.lang || 'js', 'script')}' export default script // For security concerns, we use only base name in production mode. See https://github.com/vuejs/rollup-plugin-vue/issues/258 script.__file = ${isProduction ? JSON.stringify(path.basename(filename)) : JSON.stringify(filename)} `, } : { code: '' }; if (shouldExtractCss) { input.styles = input.styles .map((style, index) => { descriptor.styles[index].code = style.code; input.script.code += '\n' + `import '${createVuePartRequest(filename, 'css', 'styles', index)}'`; if (style.module || descriptor.styles[index].scoped) { return { ...style, code: '', map: undefined }; } }) .filter(Boolean); } input.script.code = input.script.code.replace(/^\s+/gm, ''); const result = componentCompiler.assemble(compiler, filename, beforeAssemble(input), opts); descriptor.customBlocks.forEach((block, index) => { if (!isAllowed(block.type)) return; result.code += '\n' + `export * from '${createVuePartRequest(filename, (typeof block.attrs.lang === 'string' && block.attrs.lang) || createVuePartRequest.defaultLang[block.type] || block.type, 'customBlocks', index)}'`; }); dT(`id: ${filename}\ncode:\n${result.code}\n\nmap:\n${JSON.stringify(result.map, null, 2)}\n`); result.map = result.map || { mappings: '' }; return result; } }, }; } module.exports = vue; //# sourceMappingURL=rollup-plugin-vue.js.map