bm_scaffold_async_router
Version:
本木前端脚手架-异步路由版
268 lines (240 loc) • 8.56 kB
JavaScript
/**
* @Author: songqi
* @Date: 2016-10-13
* @Email: songqi@benmu-health.com
* @Last modified by: songqi
* @Last modified time: 2016-10-13
*/
var loaderUtils = require('loader-utils')
var assign = require('object-assign')
var parse = require('./parser')
var path = require('path')
var normalize = require('./normalize')
var genId = require('./gen-id')
// internal lib loaders
var selectorPath = path.resolve(__dirname, '../../../utils/', normalize.lib('selector'))
var templateLoaderPath = path.resolve(__dirname, '../../../utils/', normalize.lib('template-loader'))
var templateCompilerPath = path.resolve(__dirname, '../../../utils/', normalize.lib('template-compiler'))
var styleRewriterPath = path.resolve(__dirname, '../../../utils/', normalize.lib('style-rewriter'))
// dep loaders
var styleLoaderPath = path.resolve(__dirname, '../../../node_modules/', normalize.dep('vue-style-loader'))
var hotReloadAPIPath = path.resolve(__dirname, '../../../node_modules/', normalize.dep('vue-hot-reload-api'))
var hasBabel = false
try {
hasBabel = !!require('babel-loader')
} catch (e) {}
var hasBuble = false
try {
hasBuble = !!require('buble-loader')
} catch (e) {}
var rewriterInjectRE = /\b(css(?:-loader)?(?:\?[^!]+)?)(?:!|$)/
var defaultLang = {
template: 'html',
styles: 'css',
script: 'js'
}
var checkNamedExports =
'if (Object.keys(__vue_exports__).some(function (key) { return key !== "default" && key !== "__esModule" })) {' +
'console.error("named exports are not supported in *.vue files.")}\n'
module.exports = function (content) {
this.cacheable()
var isServer = this.options.target === 'node'
var loaderContext = this
var query = loaderUtils.parseQuery(this.query)
var options = this.options.__vueOptions__ = Object.assign({}, this.options.vue, this.vue, query)
var filePath = this.resourcePath
var fileName = path.basename(filePath)
var moduleId = 'data-v-' + genId(filePath)
var styleRewriter = styleRewriterPath + '?id=' + moduleId
var isProduction = this.minimize || process.env.NODE_ENV === 'production'
var needCssSourceMap =
!isProduction &&
this.sourceMap &&
options.cssSourceMap !== false
var bubleOptions = hasBuble && options.buble ? '?' + JSON.stringify(options.buble) : ''
var defaultLoaders = {
html: templateCompilerPath + '?id=' + moduleId,
css: styleLoaderPath + '!css-loader' + (needCssSourceMap ? '?sourceMap' : ''),
js: hasBuble ? ('buble-loader' + bubleOptions) : hasBabel ? 'babel-loader' : ''
}
// check if there are custom loaders specified via
// webpack config, otherwise use defaults
var loaders = assign({}, defaultLoaders, options.loaders)
function getRequire (type, part, index, scoped) {
return 'require(' +
getRequireString(type, part, index, scoped) +
')\n'
}
function getRequireString (type, part, index, scoped) {
return loaderUtils.stringifyRequest(loaderContext,
// disable all configuration loaders
'!!' +
// get loader string for pre-processors
getLoaderString(type, part, scoped) +
// select the corresponding part from the vue file
getSelectorString(type, index || 0) +
// the url to the actual vuefile
filePath
)
}
function getRequireForImport (type, impt, scoped) {
return 'require(' +
getRequireForImportString(type, impt, scoped) +
')\n'
}
function getRequireForImportString (type, impt, scoped) {
return loaderUtils.stringifyRequest(loaderContext,
'!!' +
getLoaderString(type, impt, scoped) +
impt.src
)
}
function getLoaderString (type, part, scoped) {
var lang = part.lang || defaultLang[type]
var loader = loaders[lang]
var rewriter = type === 'styles' ? styleRewriter + (scoped ? '&scoped=true!' : '!') : ''
var injectString = (type === 'script' && query.inject) ? 'inject!' : ''
if (loader !== undefined) {
// inject rewriter before css/html loader for
// extractTextPlugin use cases
if (rewriterInjectRE.test(loader)) {
loader = loader.replace(rewriterInjectRE, function (m, $1) {
return ensureBang($1) + rewriter
})
} else {
loader = ensureBang(loader) + rewriter
}
return injectString + ensureBang(loader)
} else {
// unknown lang, infer the loader to be used
switch (type) {
case 'template':
return defaultLoaders.html + '!' + templateLoaderPath + '?raw&engine=' + lang + '!'
case 'styles':
return defaultLoaders.css + '!' + rewriter + lang + '!'
case 'script':
return injectString + lang + '!'
}
}
}
function getSelectorString (type, index) {
return selectorPath +
'?type=' + type +
'&index=' + index + '!'
}
function ensureBang (loader) {
if (loader.charAt(loader.length - 1) !== '!') {
return loader + '!'
} else {
return loader
}
}
var parts = parse(content, fileName, this.sourceMap)
var hasScoped = parts.styles.some(function (s) { return s.scoped })
var output = 'var __vue_exports__, __vue_options__\n'
// add requires for styles
if (!isServer && parts.styles.length) {
output += '\n/* styles */\n'
parts.styles.forEach(function (style, i) {
output += style.src
? getRequireForImport('styles', style, style.scoped)
: getRequire('styles', style, i, style.scoped)
})
}
// add require for script
var script = parts.script
if (script) {
output += '\n/* script */\n'
output +=
'__vue_exports__ = ' + (
script.src
? getRequireForImport('script', script)
: getRequire('script', script)
)
}
var exports =
'__vue_options__ = __vue_exports__ = __vue_exports__ || {}\n' +
// ES6 modules interop
'if (\n' +
' typeof __vue_exports__.default === "object" ||\n' +
' typeof __vue_exports__.default === "function"\n' +
') {\n' +
(isProduction ? '' : checkNamedExports) +
'__vue_options__ = __vue_exports__ = __vue_exports__.default\n' +
'}\n' +
// constructor export interop
'if (typeof __vue_options__ === "function") {\n' +
' __vue_options__ = __vue_options__.options\n' +
'}\n' +
// add filename in dev
(isProduction ? '' : ('__vue_options__.__file = ' + JSON.stringify(filePath))) + '\n'
// add require for template
var template = parts.template
if (template) {
output += '\n/* template */\n'
output += 'var __vue_template__ = ' + (
template.src
? getRequireForImport('template', template)
: getRequire('template', template)
)
// attach render functions to exported options
exports +=
'__vue_options__.render = __vue_template__.render\n' +
'__vue_options__.staticRenderFns = __vue_template__.staticRenderFns\n'
}
// attach scoped id
if (hasScoped) {
exports += '__vue_options__._scopeId = "' + moduleId + '"\n'
}
if (!query.inject) {
output += exports
// hot reload
if (
!isServer &&
!isProduction &&
(parts.script || parts.template)
) {
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 + '", __vue_options__)\n' +
' } else {\n' +
// update
' hotAPI.reload("' + moduleId + '", __vue_options__)\n' +
' }\n' +
'})()}\n'
}
// check functional
if (!isProduction) {
output +=
'if (__vue_options__.functional) {console.error("' +
'[vue-loader] ' + fileName + ': functional components are not ' +
'supported and should be defined in plain js files using render ' +
'functions.' +
'")}\n'
}
// final export
if (options.esModule) {
output += '\nexports.__esModule = true;\nexports["default"] = __vue_exports__\n'
} else {
output += '\nmodule.exports = __vue_exports__\n'
}
} else {
// inject-loader support
output +=
'\n/* dependency injection */\n' +
'module.exports = function (injections) {\n' +
' __vue_exports__ = __vue_exports__(injections)\n' +
exports +
' return __vue_exports__\n' +
'}'
}
// done
return output
}