UNPKG

vue-svg-loader

Version:
184 lines (183 loc) 7.97 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); try { require.resolve('@vue/compiler-sfc'); } catch (e) { throw new Error('vue-loader requires @vue/compiler-sfc to be present in the dependency ' + 'tree.'); } const path_1 = __importDefault(require("path")); const querystring_1 = __importDefault(require("querystring")); const hash_sum_1 = __importDefault(require("hash-sum")); const loader_utils_1 = __importDefault(require("loader-utils")); const compiler_sfc_1 = require("@vue/compiler-sfc"); const select_1 = require("./select"); const hotReload_1 = require("./hotReload"); const cssModules_1 = require("./cssModules"); const formatError_1 = require("./formatError"); const plugin_1 = __importDefault(require("./plugin")); exports.VueLoaderPlugin = plugin_1.default; let errorEmitted = false; function loader(source) { const loaderContext = this; // check if plugin is installed if (!errorEmitted && !loaderContext['thread-loader'] && !loaderContext[plugin_1.default.NS]) { loaderContext.emitError(new Error(`vue-loader was used without the corresponding plugin. ` + `Make sure to include VueLoaderPlugin in your webpack config.`)); errorEmitted = true; } const stringifyRequest = (r) => loader_utils_1.default.stringifyRequest(loaderContext, r); const { mode, target, sourceMap, rootContext, resourcePath, resourceQuery } = loaderContext; const rawQuery = resourceQuery.slice(1); const incomingQuery = querystring_1.default.parse(rawQuery); const options = (loader_utils_1.default.getOptions(loaderContext) || {}); const isServer = target === 'node'; const isProduction = mode === 'production'; const { descriptor, errors } = compiler_sfc_1.parse(source, { filename: resourcePath, sourceMap }); if (errors.length) { errors.forEach(err => { formatError_1.formatError(err, source, resourcePath); loaderContext.emitError(err); }); return ``; } // if the query has a type field, this is a language block request // e.g. foo.vue?type=template&id=xxxxx // and we will return early if (incomingQuery.type) { return select_1.selectBlock(descriptor, loaderContext, incomingQuery, !!options.appendExtension); } // module id for scoped CSS & hot-reload const rawShortFilePath = path_1.default .relative(rootContext || process.cwd(), resourcePath) .replace(/^(\.\.[\/\\])+/, ''); const shortFilePath = rawShortFilePath.replace(/\\/g, '/') + resourceQuery; const id = hash_sum_1.default(isProduction ? shortFilePath + '\n' + source : shortFilePath); // feature information const hasScoped = descriptor.styles.some(s => s.scoped); const needsHotReload = !isServer && !isProduction && !!(descriptor.script || descriptor.template) && options.hotReload !== false; // template let templateImport = ``; let templateRequest; if (descriptor.template) { const src = descriptor.template.src || resourcePath; const idQuery = `&id=${id}`; const scopedQuery = hasScoped ? `&scoped=true` : ``; const attrsQuery = attrsToQuery(descriptor.template.attrs); const query = `?vue&type=template${idQuery}${scopedQuery}${attrsQuery}${resourceQuery}`; templateRequest = stringifyRequest(src + query); templateImport = `import { render } from ${templateRequest}`; } // script let scriptImport = `const script = {}`; if (descriptor.script) { const src = descriptor.script.src || resourcePath; const attrsQuery = attrsToQuery(descriptor.script.attrs, 'js'); const query = `?vue&type=script${attrsQuery}${resourceQuery}`; const scriptRequest = stringifyRequest(src + query); scriptImport = `import script from ${scriptRequest}\n` + `export * from ${scriptRequest}`; // support named exports } // styles let stylesCode = ``; let hasCSSModules = false; if (descriptor.styles.length) { descriptor.styles.forEach((style, i) => { const src = style.src || resourcePath; const attrsQuery = attrsToQuery(style.attrs, 'css'); // make sure to only pass id when necessary so that we don't inject // duplicate tags when multiple components import the same css file const idQuery = style.scoped ? `&id=${id}` : ``; const query = `?vue&type=style&index=${i}${idQuery}${attrsQuery}${resourceQuery}`; const styleRequest = stringifyRequest(src + query); if (style.module) { if (!hasCSSModules) { stylesCode += `\nconst cssModules = script.__cssModules = {}`; hasCSSModules = true; } stylesCode += cssModules_1.genCSSModulesCode(id, i, styleRequest, style.module, needsHotReload); } else { stylesCode += `\nimport ${styleRequest}`; } // TODO SSR critical CSS collection }); } let code = [ templateImport, scriptImport, stylesCode, templateImport ? `script.render = render` : `` ] .filter(Boolean) .join('\n'); // attach scope Id for runtime use if (hasScoped) { code += `\nscript.__scopeId = "data-v-${id}"`; } if (needsHotReload) { code += hotReload_1.genHotReloadCode(id, templateRequest); } // Expose filename. This is used by the devtools and Vue runtime warnings. if (!isProduction) { // Expose the file's full path in development, so that it can be opened // from the devtools. code += `\nscript.__file = ${JSON.stringify(rawShortFilePath.replace(/\\/g, '/'))}`; } else if (options.exposeFilename) { // Libraries can opt-in to expose their components' filenames in production builds. // For security reasons, only expose the file's basename in production. code += `\nscript.__file = ${JSON.stringify(path_1.default.basename(resourcePath))}`; } // custom blocks if (descriptor.customBlocks && descriptor.customBlocks.length) { code += `\n/* custom blocks */\n`; code += descriptor.customBlocks .map((block, i) => { const src = block.attrs.src || resourcePath; const attrsQuery = attrsToQuery(block.attrs); const blockTypeQuery = `&blockType=${querystring_1.default.escape(block.type)}`; const issuerQuery = block.attrs.src ? `&issuerPath=${querystring_1.default.escape(resourcePath)}` : ''; const query = `?vue&type=custom&index=${i}${blockTypeQuery}${issuerQuery}${attrsQuery}${resourceQuery}`; return (`import block${i} from ${stringifyRequest(src + query)}\n` + `if (typeof block${i} === 'function') block${i}(script)`); }) .join(`\n`) + `\n`; } // finalize code += `\n\nexport default script`; return code; } exports.default = loader; // these are built-in query parameters so should be ignored // if the user happen to add them as attrs const ignoreList = ['id', 'index', 'src', 'type']; function attrsToQuery(attrs, langFallback) { let query = ``; for (const name in attrs) { const value = attrs[name]; if (!ignoreList.includes(name)) { query += `&${querystring_1.default.escape(name)}=${value ? querystring_1.default.escape(String(value)) : ``}`; } } if (langFallback && !(`lang` in attrs)) { query += `&lang=${langFallback}`; } return query; }