diff options
| author | ruki <waruqi@gmail.com> | 2018-11-08 00:38:48 +0800 |
|---|---|---|
| committer | ruki <waruqi@gmail.com> | 2018-11-07 21:53:09 +0800 |
| commit | 26105034da4fcce7ac883c899d781f016559310d (patch) | |
| tree | c459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/vue-loader/lib | |
| parent | 2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff) | |
| download | xmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip | |
switch to vuepress
Diffstat (limited to 'node_modules/vue-loader/lib')
| -rw-r--r-- | node_modules/vue-loader/lib/codegen/customBlocks.js | 21 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/codegen/hotReload.js | 31 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/codegen/styleInjection.js | 114 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/codegen/utils.js | 25 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/index.d.ts | 7 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/index.js | 193 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/loaders/pitcher.js | 144 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/loaders/stylePostLoader.js | 23 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/loaders/templateLoader.js | 71 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/plugin.js | 156 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/runtime/componentNormalizer.js | 93 | ||||
| -rw-r--r-- | node_modules/vue-loader/lib/select.js | 57 |
12 files changed, 935 insertions, 0 deletions
diff --git a/node_modules/vue-loader/lib/codegen/customBlocks.js b/node_modules/vue-loader/lib/codegen/customBlocks.js new file mode 100644 index 00000000..64e78a16 --- /dev/null +++ b/node_modules/vue-loader/lib/codegen/customBlocks.js @@ -0,0 +1,21 @@ +const qs = require('querystring') +const { attrsToQuery } = require('./utils') + +module.exports = function genCustomBlocksCode ( + blocks, + resourcePath, + resourceQuery, + stringifyRequest +) { + return `\n/* custom blocks */\n` + blocks.map((block, i) => { + const src = block.attrs.src || resourcePath + const attrsQuery = attrsToQuery(block.attrs) + const issuerQuery = block.attrs.src ? `&issuerPath=${qs.escape(resourcePath)}` : '' + const inheritQuery = resourceQuery ? `&${resourceQuery.slice(1)}` : '' + const query = `?vue&type=custom&index=${i}&blockType=${qs.escape(block.type)}${issuerQuery}${attrsQuery}${inheritQuery}` + return ( + `import block${i} from ${stringifyRequest(src + query)}\n` + + `if (typeof block${i} === 'function') block${i}(component)` + ) + }).join(`\n`) + `\n` +} diff --git a/node_modules/vue-loader/lib/codegen/hotReload.js b/node_modules/vue-loader/lib/codegen/hotReload.js new file mode 100644 index 00000000..4f426b4d --- /dev/null +++ b/node_modules/vue-loader/lib/codegen/hotReload.js @@ -0,0 +1,31 @@ +const hotReloadAPIPath = JSON.stringify(require.resolve('vue-hot-reload-api')) + +const genTemplateHotReloadCode = (id, request) => { + return ` + module.hot.accept(${request}, function () { + api.rerender('${id}', { + render: render, + staticRenderFns: staticRenderFns + }) + }) + `.trim() +} + +exports.genHotReloadCode = (id, functional, templateRequest) => { + return ` +/* hot reload */ +if (module.hot) { + var api = require(${hotReloadAPIPath}) + api.install(require('vue')) + if (api.compatible) { + module.hot.accept() + if (!module.hot.data) { + api.createRecord('${id}', component.options) + } else { + api.${functional ? 'rerender' : 'reload'}('${id}', component.options) + } + ${templateRequest ? genTemplateHotReloadCode(id, templateRequest) : ''} + } +} + `.trim() +} diff --git a/node_modules/vue-loader/lib/codegen/styleInjection.js b/node_modules/vue-loader/lib/codegen/styleInjection.js new file mode 100644 index 00000000..b11e488a --- /dev/null +++ b/node_modules/vue-loader/lib/codegen/styleInjection.js @@ -0,0 +1,114 @@ +const { attrsToQuery } = require('./utils') +const hotReloadAPIPath = JSON.stringify(require.resolve('vue-hot-reload-api')) + +module.exports = function genStyleInjectionCode ( + loaderContext, + styles, + id, + resourcePath, + stringifyRequest, + needsHotReload, + needsExplicitInjection +) { + let styleImportsCode = `` + let styleInjectionCode = `` + let cssModulesHotReloadCode = `` + + let hasCSSModules = false + const cssModuleNames = new Map() + + function genStyleRequest (style, i) { + const src = style.src || resourcePath + const attrsQuery = attrsToQuery(style.attrs, 'css') + const inheritQuery = `&${loaderContext.resourceQuery.slice(1)}` + // 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}${inheritQuery}` + return stringifyRequest(src + query) + } + + function genCSSModulesCode (style, request, i) { + hasCSSModules = true + + const moduleName = style.module === true ? '$style' : style.module + if (cssModuleNames.has(moduleName)) { + loaderContext.emitError(`CSS module name ${moduleName} is not unique!`) + } + cssModuleNames.set(moduleName, true) + + // `(vue-)style-loader` exports the name-to-hash map directly + // `css-loader` exports it in `.locals` + const locals = `(style${i}.locals || style${i})` + const name = JSON.stringify(moduleName) + + if (!needsHotReload) { + styleInjectionCode += `this[${name}] = ${locals}\n` + } else { + styleInjectionCode += ` + cssModules[${name}] = ${locals} + Object.defineProperty(this, ${name}, { + get: function () { + return cssModules[${name}] + } + }) + ` + cssModulesHotReloadCode += ` + module.hot && module.hot.accept([${request}], function () { + var oldLocals = cssModules[${name}] + if (oldLocals) { + var newLocals = require(${request}) + if (JSON.stringify(newLocals) !== JSON.stringify(oldLocals)) { + cssModules[${name}] = newLocals + require(${hotReloadAPIPath}).rerender("${id}") + } + } + }) + ` + } + } + + // explicit injection is needed in SSR (for critical CSS collection) + // or in Shadow Mode (for injection into shadow root) + // In these modes, vue-style-loader exports objects with the __inject__ + // method; otherwise we simply import the styles. + if (!needsExplicitInjection) { + styles.forEach((style, i) => { + const request = genStyleRequest(style, i) + styleImportsCode += `import style${i} from ${request}\n` + if (style.module) genCSSModulesCode(style, request, i) + }) + } else { + styles.forEach((style, i) => { + const request = genStyleRequest(style, i) + styleInjectionCode += ( + `var style${i} = require(${request})\n` + + `if (style${i}.__inject__) style${i}.__inject__(context)\n` + ) + if (style.module) genCSSModulesCode(style, request, i) + }) + } + + if (!needsExplicitInjection && !hasCSSModules) { + return styleImportsCode + } + + return ` +${styleImportsCode} +${hasCSSModules && needsHotReload ? `var cssModules = {}` : ``} +${needsHotReload ? `var disposed = false` : ``} + +function injectStyles (context) { + ${needsHotReload ? `if (disposed) return` : ``} + ${styleInjectionCode} +} + +${needsHotReload ? ` + module.hot && module.hot.dispose(function (data) { + disposed = true + }) +` : ``} + +${cssModulesHotReloadCode} + `.trim() +} diff --git a/node_modules/vue-loader/lib/codegen/utils.js b/node_modules/vue-loader/lib/codegen/utils.js new file mode 100644 index 00000000..054f9a9c --- /dev/null +++ b/node_modules/vue-loader/lib/codegen/utils.js @@ -0,0 +1,25 @@ +const qs = require('querystring') + +// 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' +] + +// transform the attrs on a SFC block descriptor into a resourceQuery string +exports.attrsToQuery = (attrs, langFallback) => { + let query = `` + for (const name in attrs) { + const value = attrs[name] + if (!ignoreList.includes(name)) { + query += `&${qs.escape(name)}=${value ? qs.escape(value) : ``}` + } + } + if (langFallback && !(`lang` in attrs)) { + query += `&lang=${langFallback}` + } + return query +} diff --git a/node_modules/vue-loader/lib/index.d.ts b/node_modules/vue-loader/lib/index.d.ts new file mode 100644 index 00000000..a2755dbb --- /dev/null +++ b/node_modules/vue-loader/lib/index.d.ts @@ -0,0 +1,7 @@ +import { Plugin } from 'webpack' + +declare namespace VueLoader { + class VueLoaderPlugin extends Plugin {} +} + +export = VueLoader diff --git a/node_modules/vue-loader/lib/index.js b/node_modules/vue-loader/lib/index.js new file mode 100644 index 00000000..752f9854 --- /dev/null +++ b/node_modules/vue-loader/lib/index.js @@ -0,0 +1,193 @@ +const path = require('path') +const hash = require('hash-sum') +const qs = require('querystring') +const plugin = require('./plugin') +const selectBlock = require('./select') +const loaderUtils = require('loader-utils') +const { attrsToQuery } = require('./codegen/utils') +const { parse } = require('@vue/component-compiler-utils') +const genStylesCode = require('./codegen/styleInjection') +const { genHotReloadCode } = require('./codegen/hotReload') +const genCustomBlocksCode = require('./codegen/customBlocks') +const componentNormalizerPath = require.resolve('./runtime/componentNormalizer') +const { NS } = require('./plugin') + +let errorEmitted = false + +function loadTemplateCompiler () { + try { + return require('vue-template-compiler') + } catch (e) { + throw new Error( + `[vue-loader] vue-template-compiler must be installed as a peer dependency, ` + + `or a compatible compiler implementation must be passed via options.` + ) + } +} + +module.exports = function (source) { + const loaderContext = this + + if (!errorEmitted && !loaderContext['thread-loader'] && !loaderContext[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 => loaderUtils.stringifyRequest(loaderContext, r) + + const { + target, + request, + minimize, + sourceMap, + rootContext, + resourcePath, + resourceQuery + } = loaderContext + + const rawQuery = resourceQuery.slice(1) + const inheritQuery = `&${rawQuery}` + const incomingQuery = qs.parse(rawQuery) + const options = loaderUtils.getOptions(loaderContext) || {} + + const isServer = target === 'node' + const isShadow = !!options.shadowMode + const isProduction = options.productionMode || minimize || process.env.NODE_ENV === 'production' + const filename = path.basename(resourcePath) + const context = rootContext || process.cwd() + const sourceRoot = path.dirname(path.relative(context, resourcePath)) + + const descriptor = parse({ + source, + compiler: options.compiler || loadTemplateCompiler(), + filename, + sourceRoot, + needMap: sourceMap + }) + + // 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 selectBlock( + descriptor, + loaderContext, + incomingQuery, + !!options.appendExtension + ) + } + + // module id for scoped CSS & hot-reload + const rawShortFilePath = path + .relative(context, resourcePath) + .replace(/^(\.\.[\/\\])+/, '') + + const shortFilePath = rawShortFilePath.replace(/\\/g, '/') + resourceQuery + + const id = hash( + isProduction + ? (shortFilePath + '\n' + source) + : shortFilePath + ) + + // feature information + const hasScoped = descriptor.styles.some(s => s.scoped) + const hasFunctional = descriptor.template && descriptor.template.attrs.functional + const needsHotReload = ( + !isServer && + !isProduction && + (descriptor.script || descriptor.template) && + options.hotReload !== false + ) + + // template + let templateImport = `var render, staticRenderFns` + 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}${inheritQuery}` + const request = templateRequest = stringifyRequest(src + query) + templateImport = `import { render, staticRenderFns } from ${request}` + } + + // script + let scriptImport = `var script = {}` + if (descriptor.script) { + const src = descriptor.script.src || resourcePath + const attrsQuery = attrsToQuery(descriptor.script.attrs, 'js') + const query = `?vue&type=script${attrsQuery}${inheritQuery}` + const request = stringifyRequest(src + query) + scriptImport = ( + `import script from ${request}\n` + + `export * from ${request}` // support named exports + ) + } + + // styles + let stylesCode = `` + if (descriptor.styles.length) { + stylesCode = genStylesCode( + loaderContext, + descriptor.styles, + id, + resourcePath, + stringifyRequest, + needsHotReload, + isServer || isShadow // needs explicit injection? + ) + } + + let code = ` +${templateImport} +${scriptImport} +${stylesCode} + +/* normalize component */ +import normalizer from ${stringifyRequest(`!${componentNormalizerPath}`)} +var component = normalizer( + script, + render, + staticRenderFns, + ${hasFunctional ? `true` : `false`}, + ${/injectStyles/.test(stylesCode) ? `injectStyles` : `null`}, + ${hasScoped ? JSON.stringify(id) : `null`}, + ${isServer ? JSON.stringify(hash(request)) : `null`} + ${isShadow ? `,true` : ``} +) + `.trim() + `\n` + + if (descriptor.customBlocks && descriptor.customBlocks.length) { + code += genCustomBlocksCode( + descriptor.customBlocks, + resourcePath, + resourceQuery, + stringifyRequest + ) + } + + if (needsHotReload) { + code += `\n` + genHotReloadCode(id, hasFunctional, templateRequest) + } + + // Expose filename. This is used by the devtools and Vue runtime warnings. + code += `\ncomponent.options.__file = ${ + isProduction + // For security reasons, only expose the file's basename in production. + ? JSON.stringify(filename) + // Expose the file's full path in development, so that it can be opened + // from the devtools. + : JSON.stringify(rawShortFilePath.replace(/\\/g, '/')) + }` + + code += `\nexport default component.exports` + // console.log(code) + return code +} + +module.exports.VueLoaderPlugin = plugin diff --git a/node_modules/vue-loader/lib/loaders/pitcher.js b/node_modules/vue-loader/lib/loaders/pitcher.js new file mode 100644 index 00000000..0bc77046 --- /dev/null +++ b/node_modules/vue-loader/lib/loaders/pitcher.js @@ -0,0 +1,144 @@ +const qs = require('querystring') +const loaderUtils = require('loader-utils') +const hash = require('hash-sum') +const selfPath = require.resolve('../index') +const templateLoaderPath = require.resolve('./templateLoader') +const stylePostLoaderPath = require.resolve('./stylePostLoader') + +const isESLintLoader = l => /(\/|\\|@)eslint-loader/.test(l.path) +const isNullLoader = l => /(\/|\\|@)null-loader/.test(l.path) +const isCSSLoader = l => /(\/|\\|@)css-loader/.test(l.path) +const isPitcher = l => l.path !== __filename + +const dedupeESLintLoader = loaders => { + const res = [] + let seen = false + loaders.forEach(l => { + if (!isESLintLoader(l)) { + res.push(l) + } else if (!seen) { + seen = true + res.push(l) + } + }) + return res +} + +module.exports = code => code + +// This pitching loader is responsible for intercepting all vue block requests +// and transform it into appropriate requests. +module.exports.pitch = function (remainingRequest) { + const options = loaderUtils.getOptions(this) + const { cacheDirectory, cacheIdentifier } = options + const query = qs.parse(this.resourceQuery.slice(1)) + + let loaders = this.loaders + + // if this is a language block request, eslint-loader may get matched + // multiple times + if (query.type) { + // if this is an inline block, since the whole file itself is being linted, + // remove eslint-loader to avoid duplicate linting. + if (/\.vue$/.test(this.resourcePath)) { + loaders = loaders.filter(l => !isESLintLoader(l)) + } else { + // This is a src import. Just make sure there's not more than 1 instance + // of eslint present. + loaders = dedupeESLintLoader(loaders) + } + } + + // remove self + loaders = loaders.filter(isPitcher) + + // do not inject if user uses null-loader to void the type (#1239) + if (loaders.some(isNullLoader)) { + return + } + + const genRequest = loaders => { + // Important: dedupe since both the original rule + // and the cloned rule would match a source import request. + // also make sure to dedupe based on loader path. + // assumes you'd probably never want to apply the same loader on the same + // file twice. + // Exception: in Vue CLI we do need two instances of postcss-loader + // for user config and inline minification. So we need to dedupe baesd on + // path AND query to be safe. + const seen = new Map() + const loaderStrings = [] + + loaders.forEach(loader => { + const identifier = typeof loader === 'string' + ? loader + : (loader.path + loader.query) + const request = typeof loader === 'string' ? loader : loader.request + if (!seen.has(identifier)) { + seen.set(identifier, true) + // loader.request contains both the resolved loader path and its options + // query (e.g. ??ref-0) + loaderStrings.push(request) + } + }) + + return loaderUtils.stringifyRequest(this, '-!' + [ + ...loaderStrings, + this.resourcePath + this.resourceQuery + ].join('!')) + } + + // Inject style-post-loader before css-loader for scoped CSS and trimming + if (query.type === `style`) { + const cssLoaderIndex = loaders.findIndex(isCSSLoader) + if (cssLoaderIndex > -1) { + const afterLoaders = loaders.slice(0, cssLoaderIndex + 1) + const beforeLoaders = loaders.slice(cssLoaderIndex + 1) + const request = genRequest([ + ...afterLoaders, + stylePostLoaderPath, + ...beforeLoaders + ]) + // console.log(request) + return `import mod from ${request}; export default mod; export * from ${request}` + } + } + + // for templates: inject the template compiler & optional cache + if (query.type === `template`) { + const path = require('path') + const cacheLoader = cacheDirectory && cacheIdentifier + ? [`cache-loader?${JSON.stringify({ + // For some reason, webpack fails to generate consistent hash if we + // use absolute paths here, even though the path is only used in a + // comment. For now we have to ensure cacheDirectory is a relative path. + cacheDirectory: path.isAbsolute(cacheDirectory) + ? path.relative(process.cwd(), cacheDirectory) + : cacheDirectory, + cacheIdentifier: hash(cacheIdentifier) + '-vue-loader-template' + })}`] + : [] + const request = genRequest([ + ...cacheLoader, + templateLoaderPath + `??vue-loader-options`, + ...loaders + ]) + // console.log(request) + // the template compiler uses esm exports + return `export * from ${request}` + } + + // if a custom block has no other matching loader other than vue-loader itself, + // we should ignore it + if (query.type === `custom` && + loaders.length === 1 && + loaders[0].path === selfPath) { + return `` + } + + // When the user defines a rule that has only resourceQuery but no test, + // both that rule and the cloned rule will match, resulting in duplicated + // loaders. Therefore it is necessary to perform a dedupe here. + const request = genRequest(loaders) + return `import mod from ${request}; export default mod; export * from ${request}` +} diff --git a/node_modules/vue-loader/lib/loaders/stylePostLoader.js b/node_modules/vue-loader/lib/loaders/stylePostLoader.js new file mode 100644 index 00000000..de8d09eb --- /dev/null +++ b/node_modules/vue-loader/lib/loaders/stylePostLoader.js @@ -0,0 +1,23 @@ +const qs = require('querystring') +const { compileStyle } = require('@vue/component-compiler-utils') + +// This is a post loader that handles scoped CSS transforms. +// Injected right before css-loader by the global pitcher (../pitch.js) +// for any <style scoped> selection requests initiated from within vue files. +module.exports = function (source, inMap) { + const query = qs.parse(this.resourceQuery.slice(1)) + const { code, map, errors } = compileStyle({ + source, + filename: this.resourcePath, + id: `data-v-${query.id}`, + map: inMap, + scoped: !!query.scoped, + trim: true + }) + + if (errors.length) { + this.callback(errors[0]) + } else { + this.callback(null, code, map) + } +} diff --git a/node_modules/vue-loader/lib/loaders/templateLoader.js b/node_modules/vue-loader/lib/loaders/templateLoader.js new file mode 100644 index 00000000..d5b18741 --- /dev/null +++ b/node_modules/vue-loader/lib/loaders/templateLoader.js @@ -0,0 +1,71 @@ +const qs = require('querystring') +const loaderUtils = require('loader-utils') +const { compileTemplate } = require('@vue/component-compiler-utils') + +// Loader that compiles raw template into JavaScript functions. +// This is injected by the global pitcher (../pitch) for template +// selection requests initiated from vue files. +module.exports = function (source) { + const loaderContext = this + const query = qs.parse(this.resourceQuery.slice(1)) + + // although this is not the main vue-loader, we can get access to the same + // vue-loader options because we've set an ident in the plugin and used that + // ident to create the request for this loader in the pitcher. + const options = loaderUtils.getOptions(loaderContext) || {} + const { id } = query + const isServer = loaderContext.target === 'node' + const isProduction = loaderContext.minimize || process.env.NODE_ENV === 'production' + const isFunctional = query.functional + + // allow using custom compiler via options + const compiler = options.compiler || require('vue-template-compiler') + const compilerOptions = Object.assign({}, options.compilerOptions, { + scopeId: query.scoped ? `data-v-${id}` : null, + comments: query.comments + }) + + // for vue-component-compiler + const finalOptions = { + source, + filename: this.resourcePath, + compiler, + compilerOptions, + // allow customizing behavior of vue-template-es2015-compiler + transpileOptions: options.transpileOptions, + transformAssetUrls: options.transformAssetUrls || true, + isProduction, + isFunctional, + optimizeSSR: isServer && options.optimizeSSR !== false + } + + const compiled = compileTemplate(finalOptions) + + // tips + if (compiled.tips && compiled.tips.length) { + compiled.tips.forEach(tip => { + loaderContext.emitWarning(tip) + }) + } + + // errors + if (compiled.errors && compiled.errors.length) { + loaderContext.emitError( + `\n Error compiling template:\n${pad(compiled.source)}\n` + + compiled.errors.map(e => ` - ${e}`).join('\n') + + '\n' + ) + } + + const { code } = compiled + + // finish with ESM exports + return code + `\nexport { render, staticRenderFns }` +} + +function pad (source) { + return source + .split(/\r?\n/) + .map(line => ` ${line}`) + .join('\n') +} diff --git a/node_modules/vue-loader/lib/plugin.js b/node_modules/vue-loader/lib/plugin.js new file mode 100644 index 00000000..be2019ee --- /dev/null +++ b/node_modules/vue-loader/lib/plugin.js @@ -0,0 +1,156 @@ +const qs = require('querystring') +const RuleSet = require('webpack/lib/RuleSet') + +const id = 'vue-loader-plugin' +const NS = 'vue-loader' + +class VueLoaderPlugin { + apply (compiler) { + // add NS marker so that the loader can detect and report missing plugin + if (compiler.hooks) { + // webpack 4 + compiler.hooks.compilation.tap(id, compilation => { + compilation.hooks.normalModuleLoader.tap(id, loaderContext => { + loaderContext[NS] = true + }) + }) + } else { + // webpack < 4 + compiler.plugin('compilation', compilation => { + compilation.plugin('normal-module-loader', loaderContext => { + loaderContext[NS] = true + }) + }) + } + + // use webpack's RuleSet utility to normalize user rules + const rawRules = compiler.options.module.rules + const { rules } = new RuleSet(rawRules) + + // find the rule that applies to vue files + let vueRuleIndex = rawRules.findIndex(createMatcher(`foo.vue`)) + if (vueRuleIndex < 0) { + vueRuleIndex = rawRules.findIndex(createMatcher(`foo.vue.html`)) + } + const vueRule = rules[vueRuleIndex] + + if (!vueRule) { + throw new Error( + `[VueLoaderPlugin Error] No matching rule for .vue files found.\n` + + `Make sure there is at least one root-level rule that matches .vue or .vue.html files.` + ) + } + + if (vueRule.oneOf) { + throw new Error( + `[VueLoaderPlugin Error] vue-loader 15 currently does not support vue rules with oneOf.` + ) + } + + // get the normlized "use" for vue files + const vueUse = vueRule.use + // get vue-loader options + const vueLoaderUseIndex = vueUse.findIndex(u => { + return /^vue-loader|(\/|\\|@)vue-loader/.test(u.loader) + }) + + if (vueLoaderUseIndex < 0) { + throw new Error( + `[VueLoaderPlugin Error] No matching use for vue-loader is found.\n` + + `Make sure the rule matching .vue files include vue-loader in its use.` + ) + } + + // make sure vue-loader options has a known ident so that we can share + // options by reference in the template-loader by using a ref query like + // template-loader??vue-loader-options + const vueLoaderUse = vueUse[vueLoaderUseIndex] + vueLoaderUse.ident = 'vue-loader-options' + vueLoaderUse.options = vueLoaderUse.options || {} + + // for each user rule (expect the vue rule), create a cloned rule + // that targets the corresponding language blocks in *.vue files. + const clonedRules = rules + .filter(r => r !== vueRule) + .map(cloneRule) + + // global pitcher (responsible for injecting template compiler loader & CSS + // post loader) + const pitcher = { + loader: require.resolve('./loaders/pitcher'), + resourceQuery: query => { + const parsed = qs.parse(query.slice(1)) + return parsed.vue != null + }, + options: { + cacheDirectory: vueLoaderUse.options.cacheDirectory, + cacheIdentifier: vueLoaderUse.options.cacheIdentifier + } + } + + // replace original rules + compiler.options.module.rules = [ + pitcher, + ...clonedRules, + ...rules + ] + } +} + +function createMatcher (fakeFile) { + return (rule, i) => { + // #1201 we need to skip the `include` check when locating the vue rule + const clone = Object.assign({}, rule) + delete clone.include + const normalized = RuleSet.normalizeRule(clone, {}, '') + return ( + !rule.enforce && + normalized.resource && + normalized.resource(fakeFile) + ) + } +} + +function cloneRule (rule) { + const { resource, resourceQuery } = rule + // Assuming `test` and `resourceQuery` tests are executed in series and + // synchronously (which is true based on RuleSet's implementation), we can + // save the current resource being matched from `test` so that we can access + // it in `resourceQuery`. This ensures when we use the normalized rule's + // resource check, include/exclude are matched correctly. + let currentResource + const res = Object.assign({}, rule, { + resource: { + test: resource => { + currentResource = resource + return true + } + }, + resourceQuery: query => { + const parsed = qs.parse(query.slice(1)) + if (parsed.vue == null) { + return false + } + if (resource && parsed.lang == null) { + return false + } + const fakeResourcePath = `${currentResource}.${parsed.lang}` + if (resource && !resource(fakeResourcePath)) { + return false + } + if (resourceQuery && !resourceQuery(query)) { + return false + } + return true + } + }) + + if (rule.oneOf) { + res.oneOf = rule.oneOf.map(cloneRule) + } + + return res +} + +VueLoaderPlugin.NS = NS +module.exports = VueLoaderPlugin diff --git a/node_modules/vue-loader/lib/runtime/componentNormalizer.js b/node_modules/vue-loader/lib/runtime/componentNormalizer.js new file mode 100644 index 00000000..6e2e9e76 --- /dev/null +++ b/node_modules/vue-loader/lib/runtime/componentNormalizer.js @@ -0,0 +1,93 @@ +/* globals __VUE_SSR_CONTEXT__ */ + +// IMPORTANT: Do NOT use ES2015 features in this file (except for modules). +// This module is a runtime utility for cleaner component module output and will +// be included in the final webpack user bundle. + +export default function normalizeComponent ( + scriptExports, + render, + staticRenderFns, + functionalTemplate, + injectStyles, + scopeId, + moduleIdentifier, /* server only */ + shadowMode /* vue-cli only */ +) { + // Vue.extend constructor export interop + var options = typeof scriptExports === 'function' + ? scriptExports.options + : scriptExports + + // render functions + if (render) { + options.render = render + options.staticRenderFns = staticRenderFns + options._compiled = true + } + + // functional template + if (functionalTemplate) { + options.functional = true + } + + // scopedId + if (scopeId) { + options._scopeId = 'data-v-' + scopeId + } + + var hook + if (moduleIdentifier) { // server build + hook = function (context) { + // 2.3 injection + context = + context || // cached call + (this.$vnode && this.$vnode.ssrContext) || // stateful + (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional + // 2.2 with runInNewContext: true + if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { + context = __VUE_SSR_CONTEXT__ + } + // inject component styles + if (injectStyles) { + injectStyles.call(this, context) + } + // register component module identifier for async chunk inferrence + if (context && context._registeredComponents) { + context._registeredComponents.add(moduleIdentifier) + } + } + // used by ssr in case component is cached and beforeCreate + // never gets called + options._ssrRegister = hook + } else if (injectStyles) { + hook = shadowMode + ? function () { injectStyles.call(this, this.$root.$options.shadowRoot) } + : injectStyles + } + + if (hook) { + if (options.functional) { + // for template-only hot-reload because in that case the render fn doesn't + // go through the normalizer + options._injectStyles = hook + // register for functioal component in vue file + var originalRender = options.render + options.render = function renderWithStyleInjection (h, context) { + hook.call(context) + return originalRender(h, context) + } + } else { + // inject component registration as beforeCreate hook + var existing = options.beforeCreate + options.beforeCreate = existing + ? [].concat(existing, hook) + : [hook] + } + } + + return { + exports: scriptExports, + options: options + } +} diff --git a/node_modules/vue-loader/lib/select.js b/node_modules/vue-loader/lib/select.js new file mode 100644 index 00000000..2546c9ce --- /dev/null +++ b/node_modules/vue-loader/lib/select.js @@ -0,0 +1,57 @@ +module.exports = function selectBlock ( + descriptor, + loaderContext, + query, + appendExtension +) { + // template + if (query.type === `template`) { + if (appendExtension) { + loaderContext.resourcePath += '.' + (descriptor.template.lang || 'html') + } + loaderContext.callback( + null, + descriptor.template.content, + descriptor.template.map + ) + return + } + + // script + if (query.type === `script`) { + if (appendExtension) { + loaderContext.resourcePath += '.' + (descriptor.script.lang || 'js') + } + loaderContext.callback( + null, + descriptor.script.content, + descriptor.script.map + ) + return + } + + // styles + if (query.type === `style` && query.index != null) { + const style = descriptor.styles[query.index] + if (appendExtension) { + loaderContext.resourcePath += '.' + (style.lang || 'css') + } + loaderContext.callback( + null, + style.content, + style.map + ) + return + } + + // custom + if (query.type === 'custom' && query.index != null) { + const block = descriptor.customBlocks[query.index] + loaderContext.callback( + null, + block.content, + block.map + ) + return + } +} |
