This commit is contained in:
darenhsu
2022-07-17 13:16:16 +08:00
parent 84759556ff
commit befd344ab0
28070 changed files with 4008428 additions and 1 deletions
+7
View File
@@ -0,0 +1,7 @@
const VuetifyLoader = require('./loader')
const VuetifyLoaderPlugin = require('./plugin')
const ProgressiveLoaderModule = require('../progressive-loader/module')
module.exports = VuetifyLoader
module.exports.VuetifyLoaderPlugin = VuetifyLoaderPlugin
module.exports.VuetifyProgressiveModule = ProgressiveLoaderModule
+118
View File
@@ -0,0 +1,118 @@
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 = (await new Promise((resolve, reject) =>
this.resolve(path.dirname(this.resourcePath), component.template.src, (err, result) => {
if (err) reject(err)
else resolve(result)
})
))
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 => {
if ("directives" in node) {
node.directives.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)
}
+5
View File
@@ -0,0 +1,5 @@
const { directives } = require('./generator')
module.exports = function match (_, { kebabAttr, camelAttr: attr }) {
if (directives.includes(attr)) return [attr, `import ${attr} from 'vuetify/lib/directives/${kebabAttr}'`]
}
+36
View File
@@ -0,0 +1,36 @@
const Module = require('module')
const originalLoader = Module._load
const { readdirSync, statSync } = require('fs')
const { dirname, join } = require('path')
Module._load = function _load (request, parent) {
if (request.endsWith('.styl')) return
if (request.endsWith('.scss')) return
if (request.endsWith('.sass')) return
else return originalLoader(request, parent)
}
const directives = Object.keys(require('vuetify/es5/directives'))
.filter(val => val !== 'default')
const dir = dirname(require.resolve('vuetify/es5/components'))
const components = new Map()
readdirSync(dir).forEach(group => {
if (!statSync(join(dir, group)).isDirectory()) return
const component = require(`vuetify/es5/components/${group}`).default
if (component.hasOwnProperty('$_vuetify_subcomponents')) {
Object.keys(component.$_vuetify_subcomponents)
.forEach(name => components.set(name, group))
} else {
components.set(group, group)
}
})
Module._load = originalLoader
module.exports = {
directives,
components
}
+9
View File
@@ -0,0 +1,9 @@
const { components } = require('./generator')
module.exports = function match (_, { kebabTag, camelTag: tag }) {
if (!kebabTag.startsWith('v-')) return
if (components.has(tag)) {
return [tag, `import { ${tag} } from 'vuetify/lib/components/${components.get(tag)}';`]
}
}
+149
View File
@@ -0,0 +1,149 @@
const RuleSet = require('webpack/lib/RuleSet')
const progressiveLoaderModule = require('../progressive-loader/module')
let vueLoaderPath
try {
vueLoaderPath = require.resolve('vue-loader')
} catch (err) {}
function isVueLoader (use) {
return use.ident === 'vue-loader-options' ||
use.loader === 'vue-loader' ||
(vueLoaderPath && use.loader === vueLoaderPath)
}
class VuetifyLoaderPlugin {
constructor (options) {
this.options = options || {}
}
apply (compiler) {
// use webpack's RuleSet utility to normalize user rules
const rawRules = compiler.options.module.rules
const { rules } = new RuleSet(rawRules)
this.rules = rules
// find the rules that apply to vue files
const vueRules = rules.filter(rule => rule.use && rule.use.find(isVueLoader))
if (!vueRules.length) {
throw new Error(
`[VuetifyLoaderPlugin Error] No matching rule for vue-loader found.\n` +
`Make sure there is at least one root-level rule that uses vue-loader.`
)
}
vueRules.forEach(this.updateRule.bind(this))
compiler.options.module.rules = rules
}
updateRule (rule) {
if (this.options.progressiveImages) {
const vueLoaderOptions = rule.use.find(isVueLoader).options
vueLoaderOptions.compilerOptions = vueLoaderOptions.compilerOptions || {}
vueLoaderOptions.compilerOptions.modules = vueLoaderOptions.compilerOptions.modules || []
vueLoaderOptions.compilerOptions.modules.push(progressiveLoaderModule)
const imageRuleIndex = this.rules.findIndex(rule => {
return rule.resource &&
!rule.resourceQuery &&
['.png', '.jpg', '.jpeg', '.gif'].some(ext => rule.resource(ext))
})
let imageRule = this.rules[imageRuleIndex]
const options = typeof this.options.progressiveImages === 'boolean'
? undefined
: this.options.progressiveImages
if (!imageRule) {
imageRule = {
test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)(\?.*)?$/,
oneOf: [
{
test: /\.(png|jpe?g|gif)$/,
resourceQuery: options ? options.resourceQuery : /vuetify-preload/,
use: [
{
loader: 'vuetify-loader/progressive-loader',
options
},
{
loader: 'url-loader',
options: { limit: 8000 }
}
]
},
{
loader: 'url-loader',
options: { limit: 8000 }
}
]
}
rules.push(imageRule)
} else {
if (Array.isArray(imageRule.use)) {
imageRule.oneOf = [
{
test: /\.(png|jpe?g|gif)$/,
resourceQuery: options ? options.resourceQuery : /vuetify-preload/,
use: [
{
loader: 'vuetify-loader/progressive-loader',
options
},
...imageRule.use
]
},
...imageRule.use
]
} else if (imageRule.loader) {
imageRule.oneOf = [
{
test: /\.(png|jpe?g|gif)$/,
resourceQuery: options ? options.resourceQuery : /vuetify-preload/,
use: [
{
loader: 'vuetify-loader/progressive-loader',
options
},
{
loader: imageRule.loader,
options: imageRule.options
}
]
},
{
loader: imageRule.loader,
options: imageRule.options
}
]
}
delete imageRule.use
delete imageRule.loader
delete imageRule.options
}
}
rule.oneOf = [
{
resourceQuery: '?',
use: rule.use
},
{
use: [
{
loader: require.resolve('./loader'),
options: {
match: this.options.match || [],
attrsMatch: this.options.attrsMatch || []
}
},
...rule.use
]
},
]
delete rule.use
}
}
module.exports = VuetifyLoaderPlugin
+19
View File
@@ -0,0 +1,19 @@
// 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.
module.exports = function installComponents (component, components) {
var options = typeof component.exports === 'function'
? component.exports.extendOptions
: component.options
if (typeof component.exports === 'function') {
options.components = component.exports.options.components
}
options.components = options.components || {}
for (var i in components) {
options.components[i] = options.components[i] || components[i]
}
}
+19
View File
@@ -0,0 +1,19 @@
// 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.
module.exports = function installDirectives (component, directives) {
var options = typeof component.exports === 'function'
? component.exports.extendOptions
: component.options
if (typeof component.exports === 'function') {
options.directives = component.exports.options.directives
}
options.directives = options.directives || {}
for (var i in directives) {
options.directives[i] = options.directives[i] || directives[i]
}
}
+34
View File
@@ -0,0 +1,34 @@
/**
* Stolen from Vue
* @see https://github.com/vuejs/vue/blob/52719cca/src/shared/util.js
*/
const camelizeRE = /-(\w)/g
const camelize = str => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
}
const capitalize = str => {
return str.charAt(0).toUpperCase() + str.slice(1)
}
const hyphenateRE = /\B([A-Z])/g
const hyphenate = str => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
}
function requirePeer (name) {
try {
return require(name)
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') throw e
throw new Error(`Module "${name}" required by "vuetify-loader" not found.`)
}
}
module.exports = {
camelize,
capitalize,
hyphenate,
requirePeer
}