chushihua
This commit is contained in:
BIN
Binary file not shown.
+103
@@ -0,0 +1,103 @@
|
||||
/* globals __VUE_SSR_CONTEXT__ */
|
||||
|
||||
// IMPORTANT: Do NOT use ES2015 features in this file.
|
||||
// This module is a runtime utility for cleaner component module output and will
|
||||
// be included in the final webpack user bundle.
|
||||
|
||||
module.exports = function normalizeComponent (
|
||||
rawScriptExports,
|
||||
compiledTemplate,
|
||||
functionalTemplate,
|
||||
injectStyles,
|
||||
scopeId,
|
||||
moduleIdentifier /* server only */
|
||||
) {
|
||||
var esModule
|
||||
var scriptExports = rawScriptExports = rawScriptExports || {}
|
||||
|
||||
// ES6 modules interop
|
||||
var type = typeof rawScriptExports.default
|
||||
if (type === 'object' || type === 'function') {
|
||||
esModule = rawScriptExports
|
||||
scriptExports = rawScriptExports.default
|
||||
}
|
||||
|
||||
// Vue.extend constructor export interop
|
||||
var options = typeof scriptExports === 'function'
|
||||
? scriptExports.options
|
||||
: scriptExports
|
||||
|
||||
// render functions
|
||||
if (compiledTemplate) {
|
||||
options.render = compiledTemplate.render
|
||||
options.staticRenderFns = compiledTemplate.staticRenderFns
|
||||
options._compiled = true
|
||||
}
|
||||
|
||||
// functional template
|
||||
if (functionalTemplate) {
|
||||
options.functional = true
|
||||
}
|
||||
|
||||
// scopedId
|
||||
if (scopeId) {
|
||||
options._scopeId = scopeId
|
||||
}
|
||||
|
||||
var hook
|
||||
if (moduleIdentifier) { // server build
|
||||
hook = function (context) {
|
||||
// 2.3 injection
|
||||
context =
|
||||
context || // cached call
|
||||
(this.$vnode && this.$vnode.ssrContext) || // stateful
|
||||
(this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
|
||||
// 2.2 with runInNewContext: true
|
||||
if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
|
||||
context = __VUE_SSR_CONTEXT__
|
||||
}
|
||||
// inject component styles
|
||||
if (injectStyles) {
|
||||
injectStyles.call(this, context)
|
||||
}
|
||||
// register component module identifier for async chunk inferrence
|
||||
if (context && context._registeredComponents) {
|
||||
context._registeredComponents.add(moduleIdentifier)
|
||||
}
|
||||
}
|
||||
// used by ssr in case component is cached and beforeCreate
|
||||
// never gets called
|
||||
options._ssrRegister = hook
|
||||
} else if (injectStyles) {
|
||||
hook = injectStyles
|
||||
}
|
||||
|
||||
if (hook) {
|
||||
var functional = options.functional
|
||||
var existing = functional
|
||||
? options.render
|
||||
: options.beforeCreate
|
||||
|
||||
if (!functional) {
|
||||
// inject component registration as beforeCreate hook
|
||||
options.beforeCreate = existing
|
||||
? [].concat(existing, hook)
|
||||
: [hook]
|
||||
} else {
|
||||
// for template-only hot-reload because in that case the render fn doesn't
|
||||
// go through the normalizer
|
||||
options._injectStyles = hook
|
||||
// register for functioal component in vue file
|
||||
options.render = function renderWithStyleInjection (h, context) {
|
||||
hook.call(context)
|
||||
return existing(h, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
esModule: esModule,
|
||||
exports: scriptExports,
|
||||
options: options
|
||||
}
|
||||
}
|
||||
+719
@@ -0,0 +1,719 @@
|
||||
const path = require('path')
|
||||
const hash = require('hash-sum')
|
||||
const parse = require('./parser')
|
||||
const querystring = require('querystring')
|
||||
const loaderUtils = require('loader-utils')
|
||||
const normalize = require('./utils/normalize')
|
||||
const tryRequire = require('./utils/try-require')
|
||||
|
||||
// internal lib loaders
|
||||
const selectorPath = normalize.lib('selector')
|
||||
const styleCompilerPath = normalize.lib('style-compiler/index')
|
||||
const templateCompilerPath = normalize.lib('template-compiler/index')
|
||||
const templatePreprocessorPath = normalize.lib('template-compiler/preprocessor')
|
||||
const componentNormalizerPath = normalize.lib('component-normalizer')
|
||||
|
||||
// dep loaders
|
||||
const styleLoaderPath = normalize.dep('vue-style-loader')
|
||||
const hotReloadAPIPath = normalize.dep('vue-hot-reload-api')
|
||||
|
||||
// check whether default js loader exists
|
||||
const hasBabel = !!tryRequire('babel-loader')
|
||||
const hasBuble = !!tryRequire('buble-loader')
|
||||
|
||||
const rewriterInjectRE = /\b(css(?:-loader)?(?:\?[^!]+)?)(?:!|$)/
|
||||
|
||||
const defaultLang = {
|
||||
template: 'html',
|
||||
styles: 'css',
|
||||
script: 'js'
|
||||
}
|
||||
|
||||
const postcssExtensions = [
|
||||
'postcss', 'pcss', 'sugarss', 'sss'
|
||||
]
|
||||
|
||||
// When extracting parts from the source vue file, we want to apply the
|
||||
// loaders chained before vue-loader, but exclude some loaders that simply
|
||||
// produces side effects such as linting.
|
||||
function getRawRequest (
|
||||
{ resource, loaderIndex, loaders },
|
||||
excludedPreLoaders = /eslint-loader/
|
||||
) {
|
||||
return loaderUtils.getRemainingRequest({
|
||||
resource: resource,
|
||||
loaderIndex: loaderIndex,
|
||||
loaders: loaders.filter(loader => !excludedPreLoaders.test(loader.path))
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function (content) {
|
||||
this.cacheable()
|
||||
const isServer = this.target === 'node'
|
||||
const isProduction = this.minimize || process.env.NODE_ENV === 'production'
|
||||
|
||||
const loaderContext = this
|
||||
const query = loaderUtils.getOptions(this) || {}
|
||||
const options = Object.assign(
|
||||
{
|
||||
esModule: true
|
||||
},
|
||||
this.options.vue,
|
||||
this.vue,
|
||||
query
|
||||
)
|
||||
|
||||
// disable esModule in inject mode
|
||||
// because import/export must be top-level
|
||||
if (query.inject) {
|
||||
options.esModule = false
|
||||
}
|
||||
|
||||
// #824 avoid multiple webpack runs complaining about unknown option
|
||||
Object.defineProperty(this.options, '__vueOptions__', {
|
||||
value: options,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})
|
||||
|
||||
const rawRequest = getRawRequest(this, options.excludedPreLoaders)
|
||||
const filePath = this.resourcePath
|
||||
const fileName = path.basename(filePath)
|
||||
|
||||
const context =
|
||||
(this._compiler && this._compiler.context) ||
|
||||
this.options.context ||
|
||||
process.cwd()
|
||||
const sourceRoot = path.dirname(path.relative(context, filePath))
|
||||
const shortFilePath = path.relative(context, filePath).replace(/^(\.\.[\\\/])+/, '').replace(/\\/g, '/')
|
||||
const moduleId = 'data-v-' + hash(isProduction ? (shortFilePath + '\n' + content) : shortFilePath)
|
||||
|
||||
let cssLoaderOptions = ''
|
||||
const cssSourceMap =
|
||||
!isProduction &&
|
||||
this.sourceMap &&
|
||||
options.cssSourceMap !== false
|
||||
if (cssSourceMap) {
|
||||
cssLoaderOptions += '?sourceMap'
|
||||
}
|
||||
if (isProduction) {
|
||||
cssLoaderOptions += (cssLoaderOptions ? '&' : '?') + 'minimize'
|
||||
}
|
||||
|
||||
const bubleOptions =
|
||||
hasBuble && options.buble ? '?' + JSON.stringify(options.buble) : ''
|
||||
|
||||
let output = ''
|
||||
|
||||
const parts = parse(
|
||||
content,
|
||||
fileName,
|
||||
this.sourceMap,
|
||||
sourceRoot,
|
||||
cssSourceMap
|
||||
)
|
||||
|
||||
const hasScoped = parts.styles.some(({ scoped }) => scoped)
|
||||
const templateAttrs =
|
||||
parts.template && parts.template.attrs && parts.template.attrs
|
||||
const hasComment = templateAttrs && templateAttrs.comments
|
||||
const functionalTemplate = templateAttrs && templateAttrs.functional
|
||||
const bubleTemplateOptions = Object.assign({}, options.buble)
|
||||
bubleTemplateOptions.transforms = Object.assign(
|
||||
{},
|
||||
bubleTemplateOptions.transforms
|
||||
)
|
||||
bubleTemplateOptions.transforms.stripWithFunctional = functionalTemplate
|
||||
|
||||
const templateCompilerOptions =
|
||||
'?' +
|
||||
JSON.stringify({
|
||||
id: moduleId,
|
||||
hasScoped,
|
||||
hasComment,
|
||||
transformToRequire: options.transformToRequire,
|
||||
preserveWhitespace: options.preserveWhitespace,
|
||||
buble: bubleTemplateOptions,
|
||||
// only pass compilerModules if it's a path string
|
||||
compilerModules:
|
||||
typeof options.compilerModules === 'string'
|
||||
? options.compilerModules
|
||||
: undefined
|
||||
})
|
||||
|
||||
const defaultLoaders = {
|
||||
html: templateCompilerPath + templateCompilerOptions,
|
||||
css: options.extractCSS
|
||||
? getCSSExtractLoader()
|
||||
: styleLoaderPath + '!' + 'css-loader' + cssLoaderOptions,
|
||||
js: hasBuble
|
||||
? 'buble-loader' + bubleOptions
|
||||
: hasBabel ? 'babel-loader' : ''
|
||||
}
|
||||
|
||||
// check if there are custom loaders specified via
|
||||
// webpack config, otherwise use defaults
|
||||
const loaders = Object.assign({}, defaultLoaders, options.loaders)
|
||||
const preLoaders = options.preLoaders || {}
|
||||
const postLoaders = options.postLoaders || {}
|
||||
|
||||
const needsHotReload =
|
||||
!isServer && !isProduction && (parts.script || parts.template) && options.hotReload !== false
|
||||
if (needsHotReload) {
|
||||
output += 'var disposed = false\n'
|
||||
}
|
||||
|
||||
// add requires for styles
|
||||
let cssModules
|
||||
if (parts.styles.length) {
|
||||
let styleInjectionCode = 'function injectStyle (ssrContext) {\n'
|
||||
if (needsHotReload) {
|
||||
styleInjectionCode += ` if (disposed) return\n`
|
||||
}
|
||||
if (isServer) {
|
||||
styleInjectionCode += `var i\n`
|
||||
}
|
||||
parts.styles.forEach((style, i) => {
|
||||
// require style
|
||||
let requireString = style.src
|
||||
? getRequireForImport('styles', style, style.scoped)
|
||||
: getRequire('styles', style, i, style.scoped)
|
||||
|
||||
const hasStyleLoader = requireString.indexOf('style-loader') > -1
|
||||
const hasVueStyleLoader = requireString.indexOf('vue-style-loader') > -1
|
||||
// vue-style-loader exposes inject functions during SSR so they are
|
||||
// always called
|
||||
const invokeStyle =
|
||||
isServer && hasVueStyleLoader
|
||||
? code => `;(i=${code},i.__inject__&&i.__inject__(ssrContext),i)\n`
|
||||
: code => ` ${code}\n`
|
||||
|
||||
const moduleName = style.module === true ? '$style' : style.module
|
||||
// setCssModule
|
||||
if (moduleName) {
|
||||
if (!cssModules) {
|
||||
cssModules = {}
|
||||
if (needsHotReload) {
|
||||
output += `var cssModules = {}\n`
|
||||
}
|
||||
}
|
||||
if (moduleName in cssModules) {
|
||||
loaderContext.emitError(
|
||||
'CSS module name "' + moduleName + '" is not unique!'
|
||||
)
|
||||
styleInjectionCode += invokeStyle(requireString)
|
||||
} else {
|
||||
cssModules[moduleName] = true
|
||||
|
||||
// `(vue-)style-loader` exposes the name-to-hash map directly
|
||||
// `css-loader` exposes it in `.locals`
|
||||
// add `.locals` if the user configured to not use style-loader.
|
||||
if (!hasStyleLoader) {
|
||||
requireString += '.locals'
|
||||
}
|
||||
|
||||
if (!needsHotReload) {
|
||||
styleInjectionCode += invokeStyle(
|
||||
'this["' + moduleName + '"] = ' + requireString
|
||||
)
|
||||
} else {
|
||||
// handle hot reload for CSS modules.
|
||||
// we store the exported locals in an object and proxy to it by
|
||||
// defining getters inside component instances' lifecycle hook.
|
||||
styleInjectionCode +=
|
||||
invokeStyle(`cssModules["${moduleName}"] = ${requireString}`) +
|
||||
`Object.defineProperty(this, "${moduleName}", { get: function () { return cssModules["${moduleName}"] }})\n`
|
||||
|
||||
const requirePath = style.src
|
||||
? getRequireForImportString('styles', style, style.scoped)
|
||||
: getRequireString('styles', style, i, style.scoped)
|
||||
|
||||
output +=
|
||||
`module.hot && module.hot.accept([${requirePath}], function () {\n` +
|
||||
// 1. check if style has been injected
|
||||
` var oldLocals = cssModules["${moduleName}"]\n` +
|
||||
` if (!oldLocals) return\n` +
|
||||
// 2. re-import (side effect: updates the <style>)
|
||||
` var newLocals = ${requireString}\n` +
|
||||
// 3. compare new and old locals to see if selectors changed
|
||||
` if (JSON.stringify(newLocals) === JSON.stringify(oldLocals)) return\n` +
|
||||
// 4. locals changed. Update and force re-render.
|
||||
` cssModules["${moduleName}"] = newLocals\n` +
|
||||
` require("${hotReloadAPIPath}").rerender("${moduleId}")\n` +
|
||||
`})\n`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
styleInjectionCode += invokeStyle(requireString)
|
||||
}
|
||||
})
|
||||
styleInjectionCode += '}\n'
|
||||
output += styleInjectionCode
|
||||
}
|
||||
|
||||
// we require the component normalizer function, and call it like so:
|
||||
// normalizeComponent(
|
||||
// scriptExports,
|
||||
// compiledTemplate,
|
||||
// functionalTemplate,
|
||||
// injectStyles,
|
||||
// scopeId,
|
||||
// moduleIdentifier (server only)
|
||||
// )
|
||||
output +=
|
||||
'var normalizeComponent = require(' +
|
||||
loaderUtils.stringifyRequest(loaderContext, '!' + componentNormalizerPath) +
|
||||
')\n'
|
||||
|
||||
// <script>
|
||||
output += '/* script */\n'
|
||||
const script = parts.script
|
||||
if (script) {
|
||||
if (options.esModule) {
|
||||
output += script.src
|
||||
? (
|
||||
getNamedExportForImport('script', script) + '\n' +
|
||||
getImportForImport('script', script)
|
||||
)
|
||||
: (
|
||||
getNamedExport('script', script) + '\n' +
|
||||
getImport('script', script)
|
||||
) + '\n'
|
||||
} else {
|
||||
output +=
|
||||
'var __vue_script__ = ' +
|
||||
(script.src
|
||||
? getRequireForImport('script', script)
|
||||
: getRequire('script', script)) +
|
||||
'\n'
|
||||
}
|
||||
// inject loader interop
|
||||
if (query.inject) {
|
||||
output += '__vue_script__ = __vue_script__(injections)\n'
|
||||
}
|
||||
} else {
|
||||
output += 'var __vue_script__ = null\n'
|
||||
}
|
||||
|
||||
// <template>
|
||||
output += '/* template */\n'
|
||||
const template = parts.template
|
||||
if (template) {
|
||||
if (options.esModule) {
|
||||
output +=
|
||||
(template.src
|
||||
? getImportForImport('template', template)
|
||||
: getImport('template', template)) + '\n'
|
||||
} else {
|
||||
output +=
|
||||
'var __vue_template__ = ' +
|
||||
(template.src
|
||||
? getRequireForImport('template', template)
|
||||
: getRequire('template', template)) +
|
||||
'\n'
|
||||
}
|
||||
} else {
|
||||
output += 'var __vue_template__ = null\n'
|
||||
}
|
||||
|
||||
// template functional
|
||||
output += '/* template functional */\n'
|
||||
output +=
|
||||
'var __vue_template_functional__ = ' +
|
||||
(functionalTemplate ? 'true' : 'false') +
|
||||
'\n'
|
||||
|
||||
// style
|
||||
output += '/* styles */\n'
|
||||
output +=
|
||||
'var __vue_styles__ = ' +
|
||||
(parts.styles.length ? 'injectStyle' : 'null') +
|
||||
'\n'
|
||||
|
||||
// scopeId
|
||||
output += '/* scopeId */\n'
|
||||
output +=
|
||||
'var __vue_scopeId__ = ' +
|
||||
(hasScoped ? JSON.stringify(moduleId) : 'null') +
|
||||
'\n'
|
||||
|
||||
// moduleIdentifier (server only)
|
||||
output += '/* moduleIdentifier (server only) */\n'
|
||||
output +=
|
||||
'var __vue_module_identifier__ = ' +
|
||||
(isServer ? JSON.stringify(hash(this.request)) : 'null') +
|
||||
'\n'
|
||||
|
||||
// close normalizeComponent call
|
||||
output +=
|
||||
'var Component = normalizeComponent(\n' +
|
||||
' __vue_script__,\n' +
|
||||
' __vue_template__,\n' +
|
||||
' __vue_template_functional__,\n' +
|
||||
' __vue_styles__,\n' +
|
||||
' __vue_scopeId__,\n' +
|
||||
' __vue_module_identifier__\n' +
|
||||
')\n'
|
||||
|
||||
// development-only code
|
||||
if (!isProduction) {
|
||||
// add filename in dev
|
||||
output +=
|
||||
'Component.options.__file = ' + JSON.stringify(shortFilePath) + '\n'
|
||||
}
|
||||
|
||||
// add requires for customBlocks
|
||||
if (parts.customBlocks && parts.customBlocks.length) {
|
||||
let addedPrefix = false
|
||||
|
||||
parts.customBlocks.forEach((customBlock, i) => {
|
||||
if (loaders[customBlock.type]) {
|
||||
// require customBlock
|
||||
customBlock.src = customBlock.attrs.src
|
||||
const requireString = customBlock.src
|
||||
? getRequireForImport(customBlock.type, customBlock)
|
||||
: getRequire(customBlock.type, customBlock, i)
|
||||
|
||||
if (!addedPrefix) {
|
||||
output += '\n/* customBlocks */\n'
|
||||
addedPrefix = true
|
||||
}
|
||||
|
||||
output +=
|
||||
'var customBlock = ' + requireString + '\n' +
|
||||
'if (customBlock && customBlock.__esModule) {\n' +
|
||||
' customBlock = customBlock.default\n' +
|
||||
'}\n' +
|
||||
'if (typeof customBlock === "function") {\n' +
|
||||
' customBlock(Component)\n' +
|
||||
'}\n'
|
||||
}
|
||||
})
|
||||
|
||||
output += '\n'
|
||||
}
|
||||
|
||||
if (!query.inject) {
|
||||
// hot reload
|
||||
if (needsHotReload) {
|
||||
output +=
|
||||
'\n/* hot reload */\n' +
|
||||
'if (module.hot) {(function () {\n' +
|
||||
' var hotAPI = require("' + hotReloadAPIPath + '")\n' +
|
||||
' hotAPI.install(require("vue"), false)\n' +
|
||||
' if (!hotAPI.compatible) return\n' +
|
||||
' module.hot.accept()\n' +
|
||||
' if (!module.hot.data) {\n' +
|
||||
// initial insert
|
||||
' hotAPI.createRecord("' + moduleId + '", Component.options)\n' +
|
||||
' } else {\n'
|
||||
// update
|
||||
if (cssModules) {
|
||||
output +=
|
||||
' if (module.hot.data.cssModules && Object.keys(module.hot.data.cssModules) !== Object.keys(cssModules)) {\n' +
|
||||
' delete Component.options._Ctor\n' +
|
||||
' }\n'
|
||||
}
|
||||
output +=
|
||||
` hotAPI.${
|
||||
functionalTemplate ? 'rerender' : 'reload'
|
||||
}("${moduleId}", Component.options)\n }\n`
|
||||
// dispose
|
||||
output +=
|
||||
' module.hot.dispose(function (data) {\n' +
|
||||
(cssModules ? ' data.cssModules = cssModules\n' : '') +
|
||||
' disposed = true\n' +
|
||||
' })\n'
|
||||
output += '})()}\n'
|
||||
}
|
||||
|
||||
// final export
|
||||
if (options.esModule) {
|
||||
output += '\nexport default Component.exports\n'
|
||||
} else {
|
||||
output += '\nmodule.exports = Component.exports\n'
|
||||
}
|
||||
} else {
|
||||
// inject-loader support
|
||||
output =
|
||||
'\n/* dependency injection */\n' +
|
||||
'module.exports = function (injections) {\n' +
|
||||
output +
|
||||
'\n' +
|
||||
'\nreturn Component.exports\n}'
|
||||
}
|
||||
|
||||
// done
|
||||
return output
|
||||
|
||||
// --- helpers ---
|
||||
|
||||
function getRequire (type, part, index, scoped) {
|
||||
return 'require(' + getRequireString(type, part, index, scoped) + ')'
|
||||
}
|
||||
|
||||
function getImport (type, part, index, scoped) {
|
||||
return (
|
||||
'import __vue_' + type + '__ from ' +
|
||||
getRequireString(type, part, index, scoped)
|
||||
)
|
||||
}
|
||||
|
||||
function getNamedExport (type, part, index, scoped) {
|
||||
return (
|
||||
'export * from ' +
|
||||
getRequireString(type, part, index, scoped)
|
||||
)
|
||||
}
|
||||
|
||||
function getRequireString (type, part, index, scoped) {
|
||||
return loaderUtils.stringifyRequest(
|
||||
loaderContext,
|
||||
// disable all configuration loaders
|
||||
'!!' +
|
||||
// get loader string for pre-processors
|
||||
getLoaderString(type, part, index, scoped) +
|
||||
// select the corresponding part from the vue file
|
||||
getSelectorString(type, index || 0) +
|
||||
// the url to the actual vue file, including remaining requests
|
||||
rawRequest
|
||||
)
|
||||
}
|
||||
|
||||
function getRequireForImport (type, impt, scoped) {
|
||||
return 'require(' + getRequireForImportString(type, impt, scoped) + ')'
|
||||
}
|
||||
|
||||
function getImportForImport (type, impt, scoped) {
|
||||
return (
|
||||
'import __vue_' + type + '__ from ' +
|
||||
getRequireForImportString(type, impt, scoped)
|
||||
)
|
||||
}
|
||||
|
||||
function getNamedExportForImport (type, impt, scoped) {
|
||||
return (
|
||||
'export * from ' +
|
||||
getRequireForImportString(type, impt, scoped)
|
||||
)
|
||||
}
|
||||
|
||||
function getRequireForImportString (type, impt, scoped) {
|
||||
return loaderUtils.stringifyRequest(
|
||||
loaderContext,
|
||||
'!!' + getLoaderString(type, impt, -1, scoped) + impt.src
|
||||
)
|
||||
}
|
||||
|
||||
function addCssModulesToLoader (loader, part, index) {
|
||||
if (!part.module) return loader
|
||||
const option = options.cssModules || {}
|
||||
const DEFAULT_OPTIONS = {
|
||||
modules: true
|
||||
}
|
||||
const OPTIONS = {
|
||||
localIdentName: '[hash:base64]',
|
||||
importLoaders: true
|
||||
}
|
||||
return loader.replace(/((?:^|!)css(?:-loader)?)(\?[^!]*)?/, (m, $1, $2) => {
|
||||
// $1: !css-loader
|
||||
// $2: ?a=b
|
||||
const query = loaderUtils.parseQuery($2 || '?')
|
||||
Object.assign(query, OPTIONS, option, DEFAULT_OPTIONS)
|
||||
if (index !== -1) {
|
||||
// Note:
|
||||
// Class name is generated according to its filename.
|
||||
// Different <style> tags in the same .vue file may generate same names.
|
||||
// Append `_[index]` to class name to avoid this.
|
||||
query.localIdentName += '_' + index
|
||||
}
|
||||
return $1 + '?' + JSON.stringify(query)
|
||||
})
|
||||
}
|
||||
|
||||
function buildCustomBlockLoaderString (attrs) {
|
||||
const noSrcAttrs = Object.assign({}, attrs)
|
||||
delete noSrcAttrs.src
|
||||
const qs = querystring.stringify(noSrcAttrs)
|
||||
return qs ? '?' + qs : qs
|
||||
}
|
||||
|
||||
// stringify an Array of loader objects
|
||||
function stringifyLoaders (loaders) {
|
||||
return loaders
|
||||
.map(
|
||||
obj =>
|
||||
obj && typeof obj === 'object' && typeof obj.loader === 'string'
|
||||
? obj.loader +
|
||||
(obj.options ? '?' + JSON.stringify(obj.options) : '')
|
||||
: obj
|
||||
)
|
||||
.join('!')
|
||||
}
|
||||
|
||||
function getLoaderString (type, part, index, scoped) {
|
||||
let loader = getRawLoaderString(type, part, index, scoped)
|
||||
const lang = getLangString(type, part)
|
||||
if (preLoaders[lang]) {
|
||||
loader = loader + ensureBang(preLoaders[lang])
|
||||
}
|
||||
if (postLoaders[lang]) {
|
||||
loader = ensureBang(postLoaders[lang]) + loader
|
||||
}
|
||||
return loader
|
||||
}
|
||||
|
||||
function getLangString (type, { lang }) {
|
||||
if (type === 'script' || type === 'template' || type === 'styles') {
|
||||
return lang || defaultLang[type]
|
||||
} else {
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
function getRawLoaderString (type, part, index, scoped) {
|
||||
let lang = part.lang || defaultLang[type]
|
||||
|
||||
let styleCompiler = ''
|
||||
if (type === 'styles') {
|
||||
// style compiler that needs to be applied for all styles
|
||||
styleCompiler =
|
||||
styleCompilerPath +
|
||||
'?' +
|
||||
JSON.stringify({
|
||||
// a marker for vue-style-loader to know that this is an import from a vue file
|
||||
vue: true,
|
||||
id: moduleId,
|
||||
scoped: !!scoped,
|
||||
hasInlineConfig: !!query.postcss
|
||||
}) +
|
||||
'!'
|
||||
// normalize scss/sass/postcss if no specific loaders have been provided
|
||||
if (!loaders[lang]) {
|
||||
if (postcssExtensions.indexOf(lang) !== -1) {
|
||||
lang = 'css'
|
||||
} else if (lang === 'sass') {
|
||||
lang = 'sass?indentedSyntax'
|
||||
} else if (lang === 'scss') {
|
||||
lang = 'sass'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let loader =
|
||||
options.extractCSS && type === 'styles'
|
||||
? loaders[lang] || getCSSExtractLoader(lang)
|
||||
: loaders[lang]
|
||||
|
||||
const injectString =
|
||||
type === 'script' && query.inject ? 'inject-loader!' : ''
|
||||
|
||||
if (loader != null) {
|
||||
if (Array.isArray(loader)) {
|
||||
loader = stringifyLoaders(loader)
|
||||
} else if (typeof loader === 'object') {
|
||||
loader = stringifyLoaders([loader])
|
||||
}
|
||||
if (type === 'styles') {
|
||||
// add css modules
|
||||
loader = addCssModulesToLoader(loader, part, index)
|
||||
// inject rewriter before css loader for extractTextPlugin use cases
|
||||
if (rewriterInjectRE.test(loader)) {
|
||||
loader = loader.replace(
|
||||
rewriterInjectRE,
|
||||
(m, $1) => ensureBang($1) + styleCompiler
|
||||
)
|
||||
} else {
|
||||
loader = ensureBang(loader) + styleCompiler
|
||||
}
|
||||
}
|
||||
// if user defines custom loaders for html, add template compiler to it
|
||||
if (type === 'template' && loader.indexOf(defaultLoaders.html) < 0) {
|
||||
loader = defaultLoaders.html + '!' + loader
|
||||
}
|
||||
return injectString + ensureBang(loader)
|
||||
} else {
|
||||
// unknown lang, infer the loader to be used
|
||||
switch (type) {
|
||||
case 'template':
|
||||
return (
|
||||
defaultLoaders.html +
|
||||
'!' +
|
||||
templatePreprocessorPath +
|
||||
'?engine=' +
|
||||
lang +
|
||||
'!'
|
||||
)
|
||||
case 'styles':
|
||||
loader = addCssModulesToLoader(defaultLoaders.css, part, index)
|
||||
return loader + '!' + styleCompiler + ensureBang(ensureLoader(lang))
|
||||
case 'script':
|
||||
return injectString + ensureBang(ensureLoader(lang))
|
||||
default:
|
||||
loader = loaders[type]
|
||||
if (Array.isArray(loader)) {
|
||||
loader = stringifyLoaders(loader)
|
||||
}
|
||||
return ensureBang(loader + buildCustomBlockLoaderString(part.attrs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sass => sass-loader
|
||||
// sass-loader => sass-loader
|
||||
// sass?indentedSyntax!css => sass-loader?indentedSyntax!css-loader
|
||||
function ensureLoader (lang) {
|
||||
return lang
|
||||
.split('!')
|
||||
.map(loader =>
|
||||
loader.replace(
|
||||
/^([\w-]+)(\?.*)?/,
|
||||
(_, name, query) =>
|
||||
(/-loader$/.test(name) ? name : name + '-loader') + (query || '')
|
||||
)
|
||||
)
|
||||
.join('!')
|
||||
}
|
||||
|
||||
function getSelectorString (type, index) {
|
||||
return (
|
||||
selectorPath +
|
||||
'?type=' +
|
||||
(type === 'script' || type === 'template' || type === 'styles'
|
||||
? type
|
||||
: 'customBlocks') +
|
||||
'&index=' + index +
|
||||
'!'
|
||||
)
|
||||
}
|
||||
|
||||
function ensureBang (loader) {
|
||||
if (loader.charAt(loader.length - 1) !== '!') {
|
||||
return loader + '!'
|
||||
} else {
|
||||
return loader
|
||||
}
|
||||
}
|
||||
|
||||
function getCSSExtractLoader (lang) {
|
||||
let extractor
|
||||
const op = options.extractCSS
|
||||
// extractCSS option is an instance of ExtractTextPlugin
|
||||
if (typeof op.extract === 'function') {
|
||||
extractor = op
|
||||
} else {
|
||||
extractor = tryRequire('extract-text-webpack-plugin')
|
||||
if (!extractor) {
|
||||
throw new Error(
|
||||
'[vue-loader] extractCSS: true requires extract-text-webpack-plugin ' +
|
||||
'as a peer dependency.'
|
||||
)
|
||||
}
|
||||
}
|
||||
const langLoader = lang ? ensureBang(ensureLoader(lang)) : ''
|
||||
return extractor.extract({
|
||||
use: 'css-loader' + cssLoaderOptions + '!' + langLoader,
|
||||
fallback: 'vue-style-loader'
|
||||
})
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
+59
@@ -0,0 +1,59 @@
|
||||
const compiler = require('vue-template-compiler')
|
||||
const cache = require('lru-cache')(100)
|
||||
const hash = require('hash-sum')
|
||||
const SourceMapGenerator = require('source-map').SourceMapGenerator
|
||||
|
||||
const splitRE = /\r?\n/g
|
||||
const emptyRE = /^(?:\/\/)?\s*$/
|
||||
|
||||
module.exports = (content, filename, needMap, sourceRoot, needCSSMap) => {
|
||||
const cacheKey = hash((filename + content).replace(/\\/g, '/'))
|
||||
let output = cache.get(cacheKey)
|
||||
if (output) return output
|
||||
output = compiler.parseComponent(content, { pad: 'line' })
|
||||
if (needMap) {
|
||||
if (output.script && !output.script.src) {
|
||||
output.script.map = generateSourceMap(
|
||||
filename,
|
||||
content,
|
||||
output.script.content,
|
||||
sourceRoot
|
||||
)
|
||||
}
|
||||
if (needCSSMap && output.styles) {
|
||||
output.styles.forEach(style => {
|
||||
if (!style.src) {
|
||||
style.map = generateSourceMap(
|
||||
filename,
|
||||
content,
|
||||
style.content,
|
||||
sourceRoot
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
cache.set(cacheKey, output)
|
||||
return output
|
||||
}
|
||||
|
||||
function generateSourceMap (filename, source, generated, sourceRoot) {
|
||||
const map = new SourceMapGenerator({ sourceRoot })
|
||||
map.setSourceContent(filename, source)
|
||||
generated.split(splitRE).forEach((line, index) => {
|
||||
if (!emptyRE.test(line)) {
|
||||
map.addMapping({
|
||||
source: filename,
|
||||
original: {
|
||||
line: index + 1,
|
||||
column: 0
|
||||
},
|
||||
generated: {
|
||||
line: index + 1,
|
||||
column: 0
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return map.toJSON()
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// this is a utility loader that takes a *.vue file, parses it and returns
|
||||
// the requested language block, e.g. the content inside <template>, for
|
||||
// further processing.
|
||||
|
||||
const path = require('path')
|
||||
const parse = require('./parser')
|
||||
const loaderUtils = require('loader-utils')
|
||||
|
||||
module.exports = function (content) {
|
||||
this.cacheable()
|
||||
const query = loaderUtils.getOptions(this) || {}
|
||||
const context = (this._compiler && this._compiler.context) || this.options.context || process.cwd()
|
||||
let filename = path.basename(this.resourcePath)
|
||||
filename = filename.substring(0, filename.lastIndexOf(path.extname(filename))) + '.vue'
|
||||
const sourceRoot = path.dirname(path.relative(context, this.resourcePath))
|
||||
const parts = parse(content, filename, this.sourceMap, sourceRoot)
|
||||
let part = parts[query.type]
|
||||
if (Array.isArray(part)) {
|
||||
part = part[query.index]
|
||||
}
|
||||
this.callback(null, part.content, part.map)
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
const postcss = require('postcss')
|
||||
const loaderUtils = require('loader-utils')
|
||||
const loadPostcssConfig = require('./load-postcss-config')
|
||||
|
||||
const trim = require('./plugins/trim')
|
||||
const scopeId = require('./plugins/scope-id')
|
||||
|
||||
module.exports = function (css, map) {
|
||||
this.cacheable()
|
||||
const cb = this.async()
|
||||
|
||||
const query = loaderUtils.getOptions(this) || {}
|
||||
let vueOptions = this.options.__vueOptions__
|
||||
|
||||
if (!vueOptions) {
|
||||
if (query.hasInlineConfig) {
|
||||
this.emitError(
|
||||
`\n [vue-loader] It seems you are using HappyPack with inline postcss ` +
|
||||
`options for vue-loader. This is not supported because loaders running ` +
|
||||
`in different threads cannot share non-serializable options. ` +
|
||||
`It is recommended to use a postcss config file instead.\n` +
|
||||
`\n See http://vue-loader.vuejs.org/en/features/postcss.html#using-a-config-file for more details.\n`
|
||||
)
|
||||
}
|
||||
vueOptions = Object.assign({}, this.options.vue, this.vue)
|
||||
}
|
||||
|
||||
loadPostcssConfig(this, vueOptions.postcss)
|
||||
.then(config => {
|
||||
const plugins = config.plugins.concat(trim)
|
||||
const options = Object.assign(
|
||||
{
|
||||
to: this.resourcePath,
|
||||
from: this.resourcePath,
|
||||
map: false
|
||||
},
|
||||
config.options
|
||||
)
|
||||
|
||||
// add plugin for vue-loader scoped css rewrite
|
||||
if (query.scoped) {
|
||||
plugins.push(scopeId({ id: query.id }))
|
||||
}
|
||||
|
||||
// source map
|
||||
if (
|
||||
this.sourceMap &&
|
||||
!this.minimize &&
|
||||
vueOptions.cssSourceMap !== false &&
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
!options.map
|
||||
) {
|
||||
options.map = {
|
||||
inline: false,
|
||||
annotation: false,
|
||||
prev: map
|
||||
}
|
||||
}
|
||||
|
||||
return postcss(plugins)
|
||||
.process(css, options)
|
||||
.then(result => {
|
||||
if (result.messages) {
|
||||
result.messages.forEach(({ type, file }) => {
|
||||
if (type === 'dependency') {
|
||||
this.addDependency(file)
|
||||
}
|
||||
})
|
||||
}
|
||||
const map = result.map && result.map.toJSON()
|
||||
cb(null, result.css, map)
|
||||
return null // silence bluebird warning
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
cb(e)
|
||||
})
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
const load = require('postcss-load-config')
|
||||
|
||||
let loaded
|
||||
|
||||
function isObject (val) {
|
||||
return val && typeof val === 'object'
|
||||
}
|
||||
|
||||
module.exports = function loadPostcssConfig (loaderContext, inlineConfig = {}) {
|
||||
if (inlineConfig.useConfigFile === false) {
|
||||
return Promise.resolve({
|
||||
plugins: inlineConfig.plugins || [],
|
||||
options: inlineConfig.options || {}
|
||||
})
|
||||
}
|
||||
|
||||
if (process.env.VUE_LOADER_TEST || !loaded) {
|
||||
const config = inlineConfig.config || {}
|
||||
const ctx = { webpack: loaderContext }
|
||||
if (config.ctx) {
|
||||
ctx.options = config.ctx
|
||||
}
|
||||
loaded = load(ctx, config.path, { argv: false }).catch(err => {
|
||||
// postcss-load-config throws error when no config file is found,
|
||||
// but for us it's optional. only emit other errors
|
||||
if (err.message.indexOf('No PostCSS Config found') >= 0) {
|
||||
return
|
||||
}
|
||||
const friendlyErr = new Error(`Error loading PostCSS config: ${err.message}`)
|
||||
Error.captureStackTrace(friendlyErr, err)
|
||||
loaderContext.emitError(friendlyErr)
|
||||
})
|
||||
}
|
||||
|
||||
return loaded.then(config => {
|
||||
let plugins = []
|
||||
let options = {}
|
||||
|
||||
// inline postcss options for vue-loader
|
||||
if (typeof inlineConfig === 'function') {
|
||||
inlineConfig = inlineConfig.call(this, this)
|
||||
}
|
||||
if (Array.isArray(inlineConfig)) {
|
||||
plugins = inlineConfig
|
||||
} else if (isObject(inlineConfig)) {
|
||||
plugins =
|
||||
typeof inlineConfig.plugins === 'function'
|
||||
? inlineConfig.plugins.call(this, this)
|
||||
: inlineConfig.plugins || []
|
||||
options = inlineConfig.options || {}
|
||||
}
|
||||
|
||||
// merge postcss config file
|
||||
if (config && config.plugins) {
|
||||
plugins = plugins.concat(config.plugins)
|
||||
}
|
||||
if (config && config.options) {
|
||||
options = Object.assign({}, config.options, options)
|
||||
}
|
||||
|
||||
return {
|
||||
plugins,
|
||||
options
|
||||
}
|
||||
})
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
const postcss = require('postcss')
|
||||
const selectorParser = require('postcss-selector-parser')
|
||||
|
||||
module.exports = postcss.plugin('add-id', ({ id }) => root => {
|
||||
const keyframes = Object.create(null)
|
||||
|
||||
root.each(function rewriteSelector (node) {
|
||||
if (!node.selector) {
|
||||
// handle media queries
|
||||
if (node.type === 'atrule') {
|
||||
if (node.name === 'media' || node.name === 'supports') {
|
||||
node.each(rewriteSelector)
|
||||
} else if (/-?keyframes$/.test(node.name)) {
|
||||
// register keyframes
|
||||
keyframes[node.params] = node.params = node.params + '-' + id
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
node.selector = selectorParser(selectors => {
|
||||
selectors.each(selector => {
|
||||
let node = null
|
||||
selector.each(n => {
|
||||
// ">>>" combinator
|
||||
if (n.type === 'combinator' && n.value === '>>>') {
|
||||
n.value = ' '
|
||||
n.spaces.before = n.spaces.after = ''
|
||||
return false
|
||||
}
|
||||
// /deep/ alias for >>>, since >>> doesn't work in SASS
|
||||
if (n.type === 'tag' && n.value === '/deep/') {
|
||||
const prev = n.prev()
|
||||
if (prev && prev.type === 'combinator' && prev.value === ' ') {
|
||||
prev.remove()
|
||||
}
|
||||
n.remove()
|
||||
return false
|
||||
}
|
||||
if (n.type !== 'pseudo' && n.type !== 'combinator') {
|
||||
node = n
|
||||
}
|
||||
})
|
||||
selector.insertAfter(node, selectorParser.attribute({
|
||||
attribute: id
|
||||
}))
|
||||
})
|
||||
}).process(node.selector).result
|
||||
})
|
||||
|
||||
// If keyframes are found in this <style>, find and rewrite animation names
|
||||
// in declarations.
|
||||
// Caveat: this only works for keyframes and animation rules in the same
|
||||
// <style> element.
|
||||
if (Object.keys(keyframes).length) {
|
||||
root.walkDecls(decl => {
|
||||
// individual animation-name declaration
|
||||
if (/-?animation-name$/.test(decl.prop)) {
|
||||
decl.value = decl.value.split(',')
|
||||
.map(v => keyframes[v.trim()] || v.trim())
|
||||
.join(',')
|
||||
}
|
||||
// shorthand
|
||||
if (/-?animation$/.test(decl.prop)) {
|
||||
decl.value = decl.value.split(',')
|
||||
.map(v => {
|
||||
const vals = v.trim().split(/\s+/)
|
||||
const i = vals.findIndex(val => keyframes[val])
|
||||
if (i !== -1) {
|
||||
vals.splice(i, 1, keyframes[vals[i]])
|
||||
return vals.join(' ')
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
})
|
||||
.join(',')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
const postcss = require('postcss')
|
||||
|
||||
module.exports = postcss.plugin('trim', opts => css => {
|
||||
css.walk(({ type, raws }) => {
|
||||
if (type === 'rule' || type === 'atrule') {
|
||||
raws.before = raws.after = '\n'
|
||||
}
|
||||
})
|
||||
})
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
const prettier = require('prettier')
|
||||
const loaderUtils = require('loader-utils')
|
||||
const normalize = require('../utils/normalize')
|
||||
const compiler = require('vue-template-compiler')
|
||||
const transpile = require('vue-template-es2015-compiler')
|
||||
const hotReloadAPIPath = normalize.dep('vue-hot-reload-api')
|
||||
const transformRequire = require('./modules/transform-require')
|
||||
const transformSrcset = require('./modules/transform-srcset')
|
||||
|
||||
module.exports = function (html) {
|
||||
this.cacheable()
|
||||
const isServer = this.target === 'node'
|
||||
const isProduction = this.minimize || process.env.NODE_ENV === 'production'
|
||||
const vueOptions = this.options.__vueOptions__ || {}
|
||||
const options = loaderUtils.getOptions(this) || {}
|
||||
const needsHotReload = !isServer && !isProduction && vueOptions.hotReload !== false
|
||||
const defaultModules = [transformRequire(options.transformToRequire), transformSrcset()]
|
||||
let userModules = vueOptions.compilerModules || options.compilerModules
|
||||
|
||||
// for HappyPack cross-process use cases
|
||||
if (typeof userModules === 'string') {
|
||||
userModules = require(userModules)
|
||||
}
|
||||
|
||||
const compilerOptions = {
|
||||
preserveWhitespace: options.preserveWhitespace,
|
||||
modules: defaultModules.concat(userModules || []),
|
||||
directives:
|
||||
vueOptions.compilerDirectives || options.compilerDirectives || {},
|
||||
scopeId: options.hasScoped ? options.id : null,
|
||||
comments: options.hasComment
|
||||
}
|
||||
|
||||
const compile =
|
||||
isServer && compiler.ssrCompile && vueOptions.optimizeSSR !== false
|
||||
? compiler.ssrCompile
|
||||
: compiler.compile
|
||||
|
||||
const compiled = compile(html, compilerOptions)
|
||||
|
||||
// tips
|
||||
if (compiled.tips && compiled.tips.length) {
|
||||
compiled.tips.forEach(tip => {
|
||||
this.emitWarning(tip)
|
||||
})
|
||||
}
|
||||
|
||||
let code
|
||||
if (compiled.errors && compiled.errors.length) {
|
||||
this.emitError(
|
||||
`\n Error compiling template:\n${pad(html)}\n` +
|
||||
compiled.errors.map(e => ` - ${e}`).join('\n') +
|
||||
'\n'
|
||||
)
|
||||
code = vueOptions.esModule
|
||||
? `var esExports = {render:function(){},staticRenderFns: []}\nexport default esExports`
|
||||
: 'module.exports={render:function(){},staticRenderFns:[]}'
|
||||
} else {
|
||||
const bubleOptions = options.buble
|
||||
const stripWith = bubleOptions.transforms.stripWith !== false
|
||||
const stripWithFunctional = bubleOptions.transforms.stripWithFunctional
|
||||
|
||||
const staticRenderFns = compiled.staticRenderFns.map(fn =>
|
||||
toFunction(fn, stripWithFunctional)
|
||||
)
|
||||
|
||||
code =
|
||||
transpile(
|
||||
'var render = ' +
|
||||
toFunction(compiled.render, stripWithFunctional) +
|
||||
'\n' +
|
||||
'var staticRenderFns = [' +
|
||||
staticRenderFns.join(',') +
|
||||
']',
|
||||
bubleOptions
|
||||
) + '\n'
|
||||
|
||||
// prettify render fn
|
||||
if (!isProduction) {
|
||||
code = prettier.format(code, { semi: false, parser: 'babylon' })
|
||||
}
|
||||
|
||||
// mark with stripped (this enables Vue to use correct runtime proxy detection)
|
||||
if (!isProduction && stripWith) {
|
||||
code += `render._withStripped = true\n`
|
||||
}
|
||||
const exports = `{ render: render, staticRenderFns: staticRenderFns }`
|
||||
code += vueOptions.esModule
|
||||
? `var esExports = ${exports}\nexport default esExports`
|
||||
: `module.exports = ${exports}`
|
||||
}
|
||||
// hot-reload
|
||||
if (needsHotReload) {
|
||||
const exportsName = vueOptions.esModule ? 'esExports' : 'module.exports'
|
||||
code +=
|
||||
'\nif (module.hot) {\n' +
|
||||
' module.hot.accept()\n' +
|
||||
' if (module.hot.data) {\n' +
|
||||
' require("' + hotReloadAPIPath + '")' +
|
||||
' .rerender("' + options.id + '", ' + exportsName + ')\n' +
|
||||
' }\n' +
|
||||
'}'
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
function toFunction (code, stripWithFunctional) {
|
||||
return (
|
||||
'function (' + (stripWithFunctional ? '_h,_vm' : '') + ') {' + code + '}'
|
||||
)
|
||||
}
|
||||
|
||||
function pad (html) {
|
||||
return html
|
||||
.split(/\r?\n/)
|
||||
.map(line => ` ${line}`)
|
||||
.join('\n')
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// vue compiler module for transforming `<tag>:<attribute>` to `require`
|
||||
|
||||
const urlToRequire = require('../url-to-require')
|
||||
|
||||
const defaultOptions = {
|
||||
video: ['src', 'poster'],
|
||||
source: 'src',
|
||||
img: 'src',
|
||||
image: 'xlink:href'
|
||||
}
|
||||
|
||||
module.exports = userOptions => {
|
||||
const options = userOptions
|
||||
? Object.assign({}, defaultOptions, userOptions)
|
||||
: defaultOptions
|
||||
|
||||
return {
|
||||
postTransformNode: node => {
|
||||
transform(node, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function transform (node, options) {
|
||||
for (const tag in options) {
|
||||
if ((tag === '*' || node.tag === tag) && node.attrs) {
|
||||
const attributes = options[tag]
|
||||
if (typeof attributes === 'string') {
|
||||
node.attrs.some(attr => rewrite(attr, attributes))
|
||||
} else if (Array.isArray(attributes)) {
|
||||
attributes.forEach(item => node.attrs.some(attr => rewrite(attr, item)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rewrite (attr, name) {
|
||||
if (attr.name === name) {
|
||||
const value = attr.value
|
||||
// only transform static URLs
|
||||
if (value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') {
|
||||
attr.value = urlToRequire(value.slice(1, -1))
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// vue compiler module for transforming `img:srcset` to a number of `require`s
|
||||
|
||||
const urlToRequire = require('../url-to-require')
|
||||
|
||||
module.exports = () => ({
|
||||
postTransformNode: node => {
|
||||
transform(node)
|
||||
}
|
||||
})
|
||||
|
||||
function transform (node) {
|
||||
const tags = ['img', 'source']
|
||||
|
||||
if (tags.indexOf(node.tag) !== -1 && node.attrs) {
|
||||
node.attrs.forEach(attr => {
|
||||
if (attr.name === 'srcset') {
|
||||
// same logic as in transform-require.js
|
||||
const value = attr.value
|
||||
const isStatic = value.charAt(0) === '"' && value.charAt(value.length - 1) === '"'
|
||||
if (!isStatic) {
|
||||
return
|
||||
}
|
||||
|
||||
// http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5
|
||||
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g
|
||||
|
||||
const imageCandidates = value.substr(1, value.length - 2).split(',').map(s => {
|
||||
// The attribute value arrives here with all whitespace, except normal spaces, represented by escape sequences
|
||||
const [url, descriptor] = s.replace(escapedSpaceCharacters, ' ').trim().split(' ', 2)
|
||||
return { require: urlToRequire(url), descriptor: descriptor }
|
||||
})
|
||||
|
||||
// "require(url1)"
|
||||
// "require(url1) 1x"
|
||||
// "require(url1), require(url2)"
|
||||
// "require(url1), require(url2) 2x"
|
||||
// "require(url1) 1x, require(url2)"
|
||||
// "require(url1) 1x, require(url2) 2x"
|
||||
const code = imageCandidates.map(
|
||||
({ require, descriptor }) => `${require} + "${descriptor ? ' ' + descriptor : ''}, " + `
|
||||
).join('').slice(0, -6).concat('"').replace(/ \+ ""$/, '')
|
||||
|
||||
attr.value = code
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// loader for pre-processing templates with e.g. pug
|
||||
|
||||
const cons = require('consolidate')
|
||||
const loaderUtils = require('loader-utils')
|
||||
|
||||
module.exports = function (content) {
|
||||
this.cacheable && this.cacheable()
|
||||
const callback = this.async()
|
||||
const opt = loaderUtils.getOptions(this) || {}
|
||||
|
||||
if (!cons[opt.engine]) {
|
||||
return callback(
|
||||
new Error(
|
||||
"Template engine '" +
|
||||
opt.engine +
|
||||
"' " +
|
||||
"isn't available in Consolidate.js"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// allow passing options to the template preprocessor via `template` option
|
||||
if (this.options.__vueOptions__) {
|
||||
Object.assign(opt, this.options.__vueOptions__.template)
|
||||
}
|
||||
|
||||
// for relative includes
|
||||
opt.filename = this.resourcePath
|
||||
|
||||
cons[opt.engine].render(content, opt, (err, html) => {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
callback(null, html)
|
||||
})
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
module.exports = function urlToRequire (url) {
|
||||
// same logic as in transform-require.js
|
||||
const firstChar = url.charAt(0)
|
||||
if (firstChar === '.' || firstChar === '~' || firstChar === '@') {
|
||||
if (firstChar === '~') {
|
||||
const secondChar = url.charAt(1)
|
||||
url = url.slice(secondChar === '/' ? 2 : 1)
|
||||
}
|
||||
return `require("${url}")`
|
||||
} else {
|
||||
return `"${url}"`
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
const IS_TEST = !!process.env.VUE_LOADER_TEST
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
exports.lib = file => path.resolve(__dirname, '../', file)
|
||||
|
||||
exports.dep = dep => {
|
||||
if (IS_TEST) {
|
||||
return dep
|
||||
} else if (
|
||||
fs.existsSync(path.resolve(__dirname, '../../node_modules', dep))
|
||||
) {
|
||||
// npm 2 or npm linked
|
||||
return 'vue-loader/node_modules/' + dep
|
||||
} else {
|
||||
// npm 3
|
||||
return dep
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
const cwd = process.cwd()
|
||||
const resolve = require('resolve')
|
||||
|
||||
// attempts to first require a dep using projects cwd (when vue-loader is linked)
|
||||
// then try a normal require.
|
||||
module.exports = function tryRequire (dep) {
|
||||
let fromCwd
|
||||
try {
|
||||
fromCwd = resolve.sync(dep, { basedir: cwd })
|
||||
} catch (e) {}
|
||||
if (fromCwd) {
|
||||
return require(fromCwd)
|
||||
} else {
|
||||
try {
|
||||
return require(dep)
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user