UNPKG

auto-vue-route-sfc

Version:

Create page directories and .vue files (vue single file component / SFC) based your export router.

81 lines (77 loc) 4.52 kB
const template = require('@babel/template') const generate = require("@babel/generator").default const { packageName, importWrapperFuncName, isLowNodejsVersion, replaceAlias, hasAliaFlag } = require('./utils') const plugin = () => { return { visitor: { Program(path) { const start = path.get('body')[0] const newNode = template.statement.ast(`const {${importWrapperFuncName}, vueRouterFake} = require('${packageName}')`) start.insertBefore(newNode) }, ImportDeclaration(path) { const { node } = path const specifiers = node.specifiers const source = node.source.value let newNode = '' if (specifiers.length === 1) { // import default const specifierName = node.specifiers[0].local.name if (source === 'vue-router') { newNode = template.statement.ast(`const ${specifierName} = vueRouterFake`) } else { newNode = template.statement.ast(`const ${specifierName} = ${importWrapperFuncName}(__dirname, '${source}')`) } } else { // 存在解构 const specifierNames = node.specifiers.map(item => item.local.name) if (source === 'vue-router') { newNode = template.statement.ast(`const {${specifierNames}} = vueRouterFake`) } else { newNode = template.statement.ast(`const {${specifierNames}} = ${importWrapperFuncName}(__dirname, '${source}')`) } } path.replaceWith(newNode) }, CallExpression(path) { const { node } = path if (node.callee.name === 'require') { if (node.arguments[0].value !== packageName) { // 防止将加载自身的 require(`${packageName}`) 语句转译 const argument = node.arguments[0] const argumentCode = generate(argument).code const newNode = template.statement.ast(`${importWrapperFuncName}(__dirname, ${argumentCode})`) // 去掉所有require().default的'.default',因为在importWrapperFunc方法里,若是存在default,将直接返回default。无需在外面多取一次 const parent = path.findParent((path) => path.isMemberExpression()) if (parent && parent.node.property && parent.node.property.name === 'default') { // NOTE: 要对节点(node)进行操作,其实是要对其对应的path进行操作。 // 获取子节点的path,需使用parent.get()方法,而不是parent.node.property式的访问 // 这里parent本身就是一个path,所以直接进行get操作。 // 若是parent.node,则是获取了parent的节点, parent.node.property是访问了parent节点的属性。 // 总之,要进行操作需要用其path,单纯访问属性用其node parent.replaceWith(newNode) } else { path.replaceWith(newNode) } } } else if (node.callee.type === 'Import') { const argument = node.arguments[0] let src = generate(argument).code // 在执行阶段前将带别名的import()内路径参数进行替换,否则形如“@/xxx”的写法 在高版本nodejs里 会被解释为模块,从而在返回的promise.catch报错信息中无法读到完整的路径 if (hasAliaFlag(src)) { src = replaceAlias(src) const protocol = isLowNodejsVersion ? '' : 'file://' // 高版本nodejs要求import()本地文件必须是file协议 TODO: file协议只对windows有用, 如何适配Mac src = (protocol + src).replace(/\\/g, '\\\\') // 斜杠问题,单个\会被认为是在转义 const newNode = template.statement.ast(`import(${src})`) path.replaceWith(newNode) } } } } } } module.exports = plugin