From 33a75b671ebb5001090d248e3fcab4a14246a1b9 Mon Sep 17 00:00:00 2001 From: Adrien Foulon <6115458+Tofandel@users.noreply.github.com> Date: Tue, 12 Jul 2022 13:43:21 +0200 Subject: [PATCH] fix: load external templates (#251) fixes #250 --- lib/loader.js | 139 +++++++++++++++++++----------------------- lib/loaderStyleSSR.js | 14 +++++ lib/plugin.js | 12 +++- 3 files changed, 87 insertions(+), 78 deletions(-) create mode 100644 lib/loaderStyleSSR.js diff --git a/lib/loader.js b/lib/loader.js index 776951c..5585585 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -70,93 +70,78 @@ module.exports = async function (content, sourceMap) { options.match.push(vuetifyMatcher) options.attrsMatch.push(vuetifyAttrsMatcher) + this.addDependency(this.resourcePath) - const qs = new URLSearchParams(this.resourceQuery) - if (qs.has('vue') && qs.get('type') === 'template') { - this.addDependency(this.resourcePath) - - const matches = { - components: [], - directives: [], - } + const matches = { + components: [], + directives: [], + } - const ast = acorn.parse(content, { sourceType: 'module', ecmaVersion: 'latest' }) - acornWalk.simple(ast, { - CallExpression (node) { - if (node.callee.name === '_c') { - if (node.arguments[0].type === 'Literal') { - matches.components.push([node.arguments[0].value, node.arguments[0].start, node.arguments[0].end]) - } - if (node.arguments.length >= 2 && node.arguments[1].type === 'ObjectExpression') { - const props = node.arguments[1].properties - props.forEach(prop => { - if (prop.key.type === 'Identifier' && prop.key.name === 'directives' && prop.value.type === 'ArrayExpression') { - prop.value.elements.forEach(directive => { - if (directive.type === 'ObjectExpression') { - directive.properties.forEach(prop => { - if (prop.key.type === 'Identifier' && prop.key.name === 'name') { - matches.directives.push([prop.value.value, prop.start, prop.end]) - } - }) - } - }) - } - }) - } + const ast = acorn.parse(content, { sourceType: 'module', ecmaVersion: 'latest' }) + acornWalk.simple(ast, { + CallExpression (node) { + if (node.callee.name === '_c') { + if (node.arguments[0].type === 'Literal') { + matches.components.push([node.arguments[0].value, node.arguments[0].start, node.arguments[0].end]) + } + if (node.arguments.length >= 2 && node.arguments[1].type === 'ObjectExpression') { + const props = node.arguments[1].properties + props.forEach(prop => { + if (prop.key.type === 'Identifier' && prop.key.name === 'directives' && prop.value.type === 'ArrayExpression') { + prop.value.elements.forEach(directive => { + if (directive.type === 'ObjectExpression') { + directive.properties.forEach(prop => { + if (prop.key.type === 'Identifier' && prop.key.name === 'name') { + matches.directives.push([prop.value.value, prop.start, prop.end]) + } + }) + } + }) + } + }) } } - }) - - const components = getMatches.call(this, 'Tag', dedupe(matches.components), options.match) - const directives = getMatches.call(this, 'Attr', dedupe(matches.directives), options.attrsMatch) - - const allMatches = [...matches.components.map(v => ({ - type: 'component', - name: capitalize(camelize(v[0])), - start: v[1], - end: v[2], - })), ...matches.directives.map(v => ({ - type: 'directive', - name: capitalize(camelize(v[0])), - start: v[1], - end: v[2], - }))].sort((a, b) => a.start - b.start) - - for (let i = allMatches.length - 1; i >= 0; i--) { - const tag = allMatches[i] - if (tag.type === 'component') { - if (!components.some(c => c[0] === tag.name)) continue - content = content.slice(0, tag.start) + tag.name + content.slice(tag.end) - } else { - if (!directives.some(c => c[0] === tag.name)) continue - const indent = content.slice(0, tag.start).match(/\s*$/)[0] - content = content.slice(0, tag.start) + - 'def: ' + tag.name + ',' + - indent + content.slice(tag.start) - } - } - - const imports = [...components, ...directives] - if (imports.length) { - content = imports.map(v => v[1]).join('\n') + '\n\n' + content } + }) - if (options.registerStylesSSR) { - content += injectStylesSSR(imports) - } - } else if (options.registerStylesSSR && !this.resourceQuery) { - this.addDependency(this.resourcePath) - const newContent = 'if (render._vuetifyStyles) { render._vuetifyStyles(component) }' - - // Insert our modification before the HMR code - const hotReload = content.indexOf('/* hot reload */') - if (hotReload > -1) { - content = content.slice(0, hotReload) + newContent + '\n\n' + content.slice(hotReload) + const components = getMatches.call(this, 'Tag', dedupe(matches.components), options.match) + const directives = getMatches.call(this, 'Attr', dedupe(matches.directives), options.attrsMatch) + + const allMatches = [...matches.components.map(v => ({ + type: 'component', + name: capitalize(camelize(v[0])), + start: v[1], + end: v[2], + })), ...matches.directives.map(v => ({ + type: 'directive', + name: capitalize(camelize(v[0])), + start: v[1], + end: v[2], + }))].sort((a, b) => a.start - b.start) + + for (let i = allMatches.length - 1; i >= 0; i--) { + const tag = allMatches[i] + if (tag.type === 'component') { + if (!components.some(c => c[0] === tag.name)) continue + content = content.slice(0, tag.start) + tag.name + content.slice(tag.end) } else { - content += '\n\n' + newContent + if (!directives.some(c => c[0] === tag.name)) continue + const indent = content.slice(0, tag.start).match(/\s*$/)[0] + content = content.slice(0, tag.start) + + 'def: ' + tag.name + ',' + + indent + content.slice(tag.start) } } + const imports = [...components, ...directives] + if (imports.length) { + content = imports.map(v => v[1]).join('\n') + '\n\n' + content + } + + if (options.registerStylesSSR) { + content += injectStylesSSR(imports) + } + this.callback(null, content, sourceMap) } diff --git a/lib/loaderStyleSSR.js b/lib/loaderStyleSSR.js new file mode 100644 index 0000000..7a7d30e --- /dev/null +++ b/lib/loaderStyleSSR.js @@ -0,0 +1,14 @@ +module.exports = function (content) { + this.addDependency(this.resourcePath) + this.cacheable() + const newContent = 'if (render._vuetifyStyles) { render._vuetifyStyles(component) }' + + // Insert our modification before the HMR code + const hotReload = content.indexOf('/* hot reload */') + if (hotReload > -1) { + content = content.slice(0, hotReload) + newContent + '\n\n' + content.slice(hotReload) + } else { + content += '\n\n' + newContent + } + return content +} diff --git a/lib/plugin.js b/lib/plugin.js index 463e28c..5dca94b 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -18,8 +18,18 @@ class VuetifyLoaderPlugin { ) } + if (this.options.registerStylesSSR) { + compiler.options.module.rules.unshift({ + test: /\.vue$/, + resourceQuery: /^$/, + use: { + loader: require.resolve('./loaderStyleSSR'), + } + }) + } + compiler.options.module.rules.unshift({ - test: /\.vue$/, + resourceQuery: /vue&type=template/, use: { loader: require.resolve('./loader'), options: {