chushihua
This commit is contained in:
+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}"`
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user