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/plugin.js | |
| parent | 2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff) | |
| download | xmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip | |
switch to vuepress
Diffstat (limited to 'node_modules/vue-loader/lib/plugin.js')
| -rw-r--r-- | node_modules/vue-loader/lib/plugin.js | 156 |
1 files changed, 156 insertions, 0 deletions
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 |
