UNPKG

parcel-transformer-vue2

Version:
512 lines (429 loc) 15.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _plugin = require("@parcel/plugin"); var _nullthrows = _interopRequireDefault(require("nullthrows")); var _utils = require("@parcel/utils"); var _diagnostic = _interopRequireWildcard(require("@parcel/diagnostic")); var _sourceMap = _interopRequireDefault(require("@parcel/source-map")); var _semver = _interopRequireDefault(require("semver")); var _path = require("path"); var compiler = _interopRequireWildcard(require("./compiler")); var _consolidate = _interopRequireDefault(require("consolidate")); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const MODULE_BY_NAME_RE = /\.module\./; // TODO: Use language-specific config files during preprocessing var _default = new _plugin.Transformer({ async loadConfig({ config }) { let conf = await config.getConfig(['.vuerc', '.vuerc.json', '.vuerc.js', 'vue.config.js'], { packageKey: 'vue' }); let contents = {}; if (conf) { config.invalidateOnStartup(); contents = conf.contents; if (typeof contents !== 'object') { // TODO: codeframe throw new _diagnostic.default({ diagnostic: { message: 'Vue config should be an object.', origin: '@parcel/transformer-vue' } }); } } return { customBlocks: contents.customBlocks || {}, filePath: conf && conf.filePath }; }, canReuseAST({ ast }) { return ast.type === 'vue' && _semver.default.satisfies(ast.version, '^2.6.14'); }, async parse({ asset }) { // TODO: This parses the vue component multiple times. Fix? let code = await asset.getCode(); let parsed = compiler.parse(code, { sourceMap: true, filename: asset.filePath }); if (parsed.errors.length) { throw new _diagnostic.default({ diagnostic: parsed.errors.map(err => { return createDiagnostic(err, asset.filePath); }) }); } return { type: 'vue', version: '2.6.14', program: parsed.descriptor }; }, async transform({ asset, options, resolve, config }) { let id = (0, _utils.hashObject)({ filePath: asset.filePath }).slice(-6); let scopeId = 'data-v-' + id; let hmrId = id + '-hmr'; let basePath = (0, _path.basename)(asset.filePath); let { template, script, styles, customBlocks } = (0, _nullthrows.default)((await asset.getAST())).program; if (asset.pipeline != null) { return processPipeline({ asset, template, script, styles, customBlocks, config, basePath, options, resolve, id, hmrId }); } return [{ type: 'js', uniqueKey: asset.id + '-glue', content: ` let script; let initialize = () => { script = ${script != null ? `require('script:./${basePath}'); if (script.__esModule) script = script.default` : '{}'}; ${template != null ? `script.render = require('template:./${basePath}').render; script.staticRenderFns = require('template:./${basePath}').staticRenderFns; script._scopeId = "${scopeId}"; ` : ''} ${styles.length !== 0 ? `script.__cssModules = require('style:./${basePath}').default;` : ''} ${customBlocks != null ? `require('custom:./${basePath}').default(script);` : ''} script.__scopeId = '${scopeId}'; script.__file = ${JSON.stringify(options.mode === 'production' ? basePath : asset.filePath)}; }; initialize(); ${options.hmrOptions ? `if (module.hot) { script.__hmrId = '${hmrId}'; if(!window.__VUE_HMR_RUNTIME__) { const api = require('vue-hot-reload-api') const Vue = require('vue') api.install(Vue) window.__VUE_HMR_RUNTIME__ = api; } window.__VUE_HMR_RUNTIME__.createRecord('${hmrId}', script); module.hot.accept(() => { setTimeout(() => { initialize(); // window.location.reload(); window.__VUE_HMR_RUNTIME__.reload('${hmrId}', script); }, 0); }); }` : ''} export default script;` }]; } }); exports.default = _default; function createDiagnostic(err, filePath) { if (typeof err === 'string') { return { message: err, origin: '@parcel/transformer-vue', filePath }; } // TODO: codeframe let diagnostic = { message: (0, _diagnostic.escapeMarkdown)(err.message), origin: '@parcel/transformer-vue', name: err.name, stack: err.stack }; if (err.loc) { diagnostic.codeFrames = [{ codeHighlights: [{ start: { line: err.loc.start.line + err.loc.start.offset, column: err.loc.start.column }, end: { line: err.loc.end.line + err.loc.end.offset, column: err.loc.end.column } }] }]; } return diagnostic; } async function processPipeline({ asset, template, script, styles, customBlocks, config, basePath, options, resolve, id, hmrId }) { switch (asset.pipeline) { case 'template': { let isFunctional = template.functional; if (template.src) { template.content = (await options.inputFS.readFile((await resolve(asset.filePath, template.src)))).toString(); template.lang = (0, _path.extname)(template.src).slice(1); } let content = template.content; if (template.lang && !['htm', 'html'].includes(template.lang)) { let preprocessor = _consolidate.default[template.lang]; if (!preprocessor) { // TODO: codeframe throw new _diagnostic.default({ diagnostic: { message: (0, _diagnostic.md)`Unknown template language: "${template.lang}"`, origin: '@parcel/transformer-vue' } }); } content = await preprocessor.render(content, {}); } let templateComp = compiler.compileTemplate({ filename: asset.filePath, source: content, inMap: template.src ? undefined : template.map, scoped: styles.some(style => style.scoped), isFunctional, id }); if (templateComp.errors.length) { throw new _diagnostic.default({ diagnostic: templateComp.errors.map(err => { return createDiagnostic(err, asset.filePath); }) }); } let templateAsset = _objectSpread(_objectSpread({ type: 'js', uniqueKey: asset.id + '-template' }, !template.src && asset.env.sourceMap && { map: createMap(templateComp.map, options.projectRoot) }), {}, { content: templateComp.code + '\nexports.render = render;\nexports.staticRenderFns = staticRenderFns;\n' + ` ${options.hmrOptions ? `if (module.hot) { module.hot.accept(() => { // window.location.reload(); if(!window.__VUE_HMR_RUNTIME__) { const api = require('vue-hot-reload-api') const Vue = require('vue') api.install(Vue) window.__VUE_HMR_RUNTIME__ = api; } window.__VUE_HMR_RUNTIME__.rerender('${hmrId}', exports); }) }` : ''}` }); return [templateAsset]; } case 'script': { if (script.src) { script.content = (await options.inputFS.readFile((await resolve(asset.filePath, script.src)))).toString(); script.lang = (0, _path.extname)(script.src).slice(1); } let type; switch (script.lang || 'js') { case 'javascript': case 'js': type = 'js'; break; case 'jsx': type = 'jsx'; break; case 'typescript': case 'ts': type = 'ts'; break; case 'tsx': type = 'tsx'; break; case 'coffeescript': case 'coffee': type = 'coffee'; break; default: // TODO: codeframe throw new _diagnostic.default({ diagnostic: { message: (0, _diagnostic.md)`Unknown script language: "${script.lang}"`, origin: '@parcel/transformer-vue' } }); } let scriptAsset = _objectSpread({ type, uniqueKey: asset.id + '-script', content: script.content }, !script.src && asset.env.sourceMap && { map: createMap(script.map, options.projectRoot) }); return [scriptAsset]; } case 'style': { let cssModules = {}; let assets = await Promise.all(styles.map(async (style, i) => { if (style.src) { style.content = (await options.inputFS.readFile((await resolve(asset.filePath, style.src)))).toString(); if (!style.module) { style.module = MODULE_BY_NAME_RE.test(style.src); } style.lang = (0, _path.extname)(style.src).slice(1); } switch (style.lang) { case 'less': case 'stylus': case 'styl': case 'scss': case 'sass': case 'css': case undefined: break; default: // TODO: codeframe throw new _diagnostic.default({ diagnostic: { message: (0, _diagnostic.md)`Unknown style language: "${style.lang}"`, origin: '@parcel/transformer-vue' } }); } let styleComp = await compiler.compileStyle({ filename: asset.filePath, source: style.content, modules: style.module, preprocessLang: style.lang || 'css', scoped: style.scoped ? true : false, map: style.src ? undefined : style.map, id: 'data-v-' + id }); if (styleComp.errors.length) { throw new _diagnostic.default({ diagnostic: styleComp.errors.map(err => { return createDiagnostic(err, asset.filePath); }) }); } let styleAsset = _objectSpread(_objectSpread({ type: 'css', content: styleComp.code, sideEffects: true }, !style.src && asset.env.sourceMap && { map: createMap(style.map, options.projectRoot) }), {}, { uniqueKey: asset.id + '-style' + i }); if (styleComp.modules) { if (typeof style.module === 'boolean') style.module = '$style'; cssModules[style.module] = _objectSpread(_objectSpread({}, cssModules[style.module]), styleComp.modules); } return styleAsset; })); if (Object.keys(cssModules).length !== 0) { assets.push({ type: 'js', uniqueKey: asset.id + '-cssModules', content: ` import {render} from 'template:./${basePath}'; let cssModules = ${JSON.stringify(cssModules)}; ${options.hmrOptions ? `if (module.hot) { module.hot.accept(() => { // window.location.reload(); if(!window.__VUE_HMR_RUNTIME__) { const api = require('vue-hot-reload-api') const Vue = require('vue') api.install(Vue) window.__VUE_HMR_RUNTIME__ = api; } window.__VUE_HMR_RUNTIME__.rerender('${hmrId}', render); }); };` : ''} export default cssModules;` }); } return assets; } case 'custom': { let toCall = []; // To satisfy flow if (!config) return []; let types = new Set(); for (let block of customBlocks) { let { type, src, content, attrs } = block; if (!config.customBlocks[type]) { // TODO: codeframe throw new _diagnostic.default({ diagnostic: { message: (0, _diagnostic.md)`No preprocessor found for block type ${type}`, origin: '@parcel/transformer-vue' } }); } if (src) { content = (await options.inputFS.readFile((await resolve(asset.filePath, src)))).toString(); } toCall.push([type, content, attrs]); types.add(type); } return [{ type: 'js', uniqueKey: asset.id + '-custom', content: ` let NOOP = () => {}; ${(await Promise.all([...types].map(async type => `import p${type} from './${(0, _path.relative)((0, _path.dirname)(asset.filePath), (await resolve((0, _nullthrows.default)(config.filePath), config.customBlocks[type])))}'; if (typeof p${type} !== 'function') { p${type} = NOOP; }`))).join('\n')} export default script => { ${toCall.map(([type, content, attrs]) => ` p${type}(script, ${JSON.stringify(content)}, ${JSON.stringify(attrs)});`).join('\n')} }` }]; } default: { return []; } } } function createMap(rawMap, projectRoot) { let newMap = new _sourceMap.default(projectRoot); if (rawMap) newMap.addVLQMap(rawMap); return newMap; }