Skip to content

Commit

Permalink
fix: load external templates (#251)
Browse files Browse the repository at this point in the history
fixes #250
  • Loading branch information
Tofandel authored Jul 12, 2022
1 parent fd2bd7f commit 33a75b6
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 78 deletions.
139 changes: 62 additions & 77 deletions lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
14 changes: 14 additions & 0 deletions lib/loaderStyleSSR.js
Original file line number Diff line number Diff line change
@@ -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
}
12 changes: 11 additions & 1 deletion lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down

0 comments on commit 33a75b6

Please sign in to comment.