111 lines
3.6 KiB
JavaScript
111 lines
3.6 KiB
JavaScript
const path = require('path')
|
|
const loaderUtils = require('loader-utils')
|
|
const compiler = require('vue-template-compiler')
|
|
|
|
const vuetifyMatcher = require('./matcher/tag')
|
|
const vuetifyAttrsMatcher = require('./matcher/attr')
|
|
const { camelize, capitalize, hyphenate, requirePeer } = require('./util')
|
|
const runtimePaths = {
|
|
installComponents: require.resolve('./runtime/installComponents'),
|
|
installDirectives: require.resolve('./runtime/installDirectives')
|
|
}
|
|
|
|
function getMatches (type, items, matches, component) {
|
|
const imports = []
|
|
|
|
items.forEach(item => {
|
|
for (const matcher of matches) {
|
|
const match = matcher(item, {
|
|
[`kebab${type}`]: hyphenate(item),
|
|
[`camel${type}`]: capitalize(camelize(item)),
|
|
path: this.resourcePath.substring(this.rootContext.length + 1),
|
|
component
|
|
})
|
|
if (match) {
|
|
imports.push(match)
|
|
break
|
|
}
|
|
}
|
|
})
|
|
|
|
imports.sort((a, b) => a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0))
|
|
return imports
|
|
}
|
|
|
|
function install (install, content, imports) {
|
|
if (imports.length) {
|
|
let newContent = '/* vuetify-loader */\n'
|
|
newContent += `import ${install} from ${loaderUtils.stringifyRequest(this, '!' + runtimePaths[install])}\n`
|
|
newContent += imports.map(i => i[1]).join('\n') + '\n'
|
|
newContent += `${install}(component, {${imports.map(i => i[0]).join(',')}})\n`
|
|
|
|
// 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
|
|
}
|
|
|
|
module.exports = async function (content, sourceMap) {
|
|
this.async()
|
|
this.cacheable()
|
|
|
|
const options = {
|
|
match: [],
|
|
attrsMatch: [],
|
|
...loaderUtils.getOptions(this)
|
|
}
|
|
|
|
if (!Array.isArray(options.match)) options.match = [options.match]
|
|
if (!Array.isArray(options.attrsMatch)) options.attrsMatch = [options.attrsMatch]
|
|
|
|
options.match.push(vuetifyMatcher)
|
|
options.attrsMatch.push(vuetifyAttrsMatcher)
|
|
|
|
if (!this.resourceQuery) {
|
|
const readFile = path => new Promise((resolve, reject) => {
|
|
this.fs.readFile(path, function (err, data) {
|
|
if (err) reject(err)
|
|
else resolve(data)
|
|
})
|
|
})
|
|
|
|
this.addDependency(this.resourcePath)
|
|
|
|
const tags = new Set()
|
|
const attrs = new Set()
|
|
const file = (await readFile(this.resourcePath)).toString('utf8')
|
|
const component = compiler.parseComponent(file)
|
|
if (component.template) {
|
|
if (component.template.src) {
|
|
const externalFile = path.resolve(path.dirname(this.resourcePath), component.template.src);
|
|
const externalContent = (await readFile(externalFile)).toString('utf8')
|
|
component.template.content = externalContent
|
|
}
|
|
if (component.template.lang === 'pug') {
|
|
const pug = requirePeer('pug')
|
|
try {
|
|
component.template.content = pug.render(component.template.content, {filename: this.resourcePath})
|
|
} catch (err) {/* Ignore compilation errors, they'll be picked up by other loaders */}
|
|
}
|
|
compiler.compile(component.template.content, {
|
|
modules: [{
|
|
postTransformNode: node => {
|
|
node.attrsList.forEach(({ name }) => attrs.add(name))
|
|
tags.add(node.tag)
|
|
}
|
|
}]
|
|
})
|
|
}
|
|
|
|
content = install.call(this, 'installComponents', content, getMatches.call(this, 'Tag', tags, options.match, component))
|
|
content = install.call(this, 'installDirectives', content, getMatches.call(this, 'Attr', attrs, options.attrsMatch, component))
|
|
}
|
|
|
|
this.callback(null, content, sourceMap)
|
|
}
|