如何获取vue单文件自身源码路径


Posted in Javascript onMay 06, 2019

这个问题要从一个想法说起。

D2Admin 是一个开源的,前端中后台集成方案,原先是基于 vue-cli2,大概是向 vue-cli3 过渡时,
作者老李,想在页面右下角加个 Toggle 点击,跳到当前页面源码对应的 github 页面。

确实很实用的功能,D2Admin 的 Demo 页面太多了,想看某个页面的源码,对于不熟悉项目目录结构的新手很不友好。
这些页面统一为 .vue 组件,那么转换一下:如何获取 vue 单文件自身源码路径?

目前经历了三个方案,最终目标是把自身路径赋值到 this.$options.__source 上。目前方案 3 是最新的。

方案 1 :node + __filename

直接使用 node 中的 __filename 变量:

<template>
 <h1>{{ $options.__source }}</h1>
</template>

<script>
export default {
 mounted() {
  this.$options.__source = __filename
 }
}
</script>

因为 webpack 编译时,会把源码文件在内部转为 node 模块,.vue 文件中的 script 内容也被转换了,
其中的 __filename 在编译时被运行,直接得到当前文件自身路径。

使用这个变量还需要在 webpack 配置中启用 node.__filename:

/* vue.config.js */
module.exports = {
 // ...
 chainWebpack: config => {
  // ...
  config.node
   .set('__dirname', true) // 同理
   .set('__filename', true)
 }
};

缺点

  1. 要在每个组件里手动赋值,还不能用 mixin
  2. __filename 得到的路径在部分 .vue 文件下并不准确,路径可能还会带附带 querystring

一开始,坚强的老李用这个方式,给上百个组件手动挂上了路径,但总比手动写死每个路径要好

方案 2 :vue-loader + exposeFilename

在 loader 层面,其实 vue-loader 提供了一个 exposeFilename 选项,只要启用,
就会给每个 .vue 组件带上 this.$options.__file,上面有准确的路径。
这样只需要改 loader 配置:

/* vue.config.js */
module.exports = {
 // ...
 chainWebpack: config => {
  // ...
  config.module
   .rule('vue')
   .use('vue-loader')
    .loader('vue-loader')
    .tap(options => {
     options.exposeFilename = true
     return options
    })
 }
};

开发环境默认是开启 exposeFilename 的。

此时组件内应该直接取 this.$options.__file,内容大致为 src/foo/bar.vue。

缺点

为了安全,vue-loader 在生产环境将 __file 赋值为文件名,非路径名,详见文档

后来得知这个方法,老李就第一时间改代码,删了方案 1 中的所有附加代码,结果发现生产环境结果不一致,翻车了orz

方案 3 :loader + Custom Block

既然方案 2 不让在生产环境用,那就自己写 loader 去加上这个源码路径,这里采用了Custom Block。

这个方法是慢慢调试自定义的 loader 摸索出来的,先在 vue-loader 之前加自定义的 loader A,

去注入 Custom Block 代码,再在全局加入一个针对该 Custom Block 的 loader B。

这里将方案封装,在 chainWebpack 中调用即可:

/* vue.config.js */
const VueFilenameInjector = require('./path/to/vue-filename-injector')

module.exports = {
 chainWebpack: config => {
  VueFilenameInjector(config, {
   propName: '__source' // default
  })
 }
}

源码参考:@d2-projects/d2-advance/tools/vue-filename-injector

.
└── vue-filename-injector
  ├── README.md
  ├── index.js
  └── src
    ├── index.js
    └── lib
      ├── config.js
      ├── injector.js
      └── loader.js

vue-filename-injector/index.js:

const { blockName } = require('./lib/config.js')

// for chainWebpack
module.exports = function(config, options) {
 // 注入
 config.module
  .rule('vue')
  .use('vue-filename-injector')
  .loader(require.resolve('./lib/injector.js'))
  .options(options)
  .after('vue-loader') // 不知为何 .before() 不是预期的结果,这里就绕了一下
  .end()
 // 解析
 config.module
  .rule('')
  .resourceQuery(new RegExp(`blockType=${blockName}`))
  .use('vue-filename-injector-loader')
  .loader(require.resolve('./lib/loader.js'))
  .end()
}

vue-filename-injector/lib/config.js:

const defaultPropName = '__source'
const blockName = 'vue-filename-injector'

module.exports = {
 defaultPropName,
 blockName
}

vue-filename-injector/lib/injector.js,源码部分来自 vue-loader:

const path = require('path')
const loaderUtils = require('loader-utils')

const { blockName, defaultPropName } = require('./config.js')

module.exports = function (content /*, map, meta */) {
 const loaderContext = this

 const {
  rootContext,
  resourcePath
 } = loaderContext

 const context = rootContext || process.cwd()
 const options = loaderUtils.getOptions(loaderContext) || {}
 const rawShortFilePath = path
  .relative(context, resourcePath)
  .replace(/^(\.\.[\/\\])+/, '')

 const propName = options.propName || defaultPropName

 content += `
<${blockName}>
export default function (Component) {
 Component.options.${propName} = ${JSON.stringify(rawShortFilePath.replace(/\\/g, '/'))}
}
</${blockName}>
`
 return content
}

vue-filename-injector/lib/loader.js:

module.exports = function(source, map) {
 this.callback(null, source, map)
}

相关仓库

可进入预览页面查看效果,在右下角有 Toggle

github.com/d2-projects… (可能还在翻车中)

github.com/d2-projects…

总结

目前看来,用自定义 loader 去注入代码是最便捷的方案,不用在每个组件中手写重复的代码。

由于 vue-cli3 采用 chainWebpack,加上个人对 webpack 的理解更是不深,暂时采用方案 3。

以上所述是小编给大家介绍的如何获取vue单文件自身源码路径详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery实现奇偶行赋值不同css值
Feb 17 Javascript
解析Jquery取得iframe中元素的几种方法
Jul 04 Javascript
jquery ui dialog实现弹窗特效的思路及代码
Aug 03 Javascript
超级简单实现JavaScript MVC 样式框架
Mar 24 Javascript
jquery计算出left和top,让一个div水平垂直居中的简单实例
Jul 13 Javascript
Jquery针对tr td的一些实用操作方法(必看篇)
Oct 05 Javascript
JS验证图片格式和大小并预览的简单实例
Oct 11 Javascript
Bootstrap布局之栅格系统学习笔记
May 04 Javascript
微信分享调用jssdk实例
Jun 08 Javascript
this在vue和小程序中的使用详解
Jan 28 Javascript
通过实例解析chrome如何在mac环境中安装vue-devtools插件
Jul 10 Javascript
在Vue中使用CSS3实现内容无缝滚动的示例代码
Nov 27 Vue.js
详解vue-cli中使用rem,vue自适应
May 06 #Javascript
用Vue编写抽象组件的方法
May 06 #Javascript
JS解惑之Object中的key是有序的么
May 06 #Javascript
微信小程序和百度的语音识别接口详解
May 06 #Javascript
微信小程序生成海报分享朋友圈的实现方法
May 06 #Javascript
vue项目打包后上传至GitHub并实现github-pages的预览
May 06 #Javascript
Vue实现购物车的全选、单选、显示商品价格代码实例
May 06 #Javascript
You might like
php中的注释、变量、数组、常量、函数应用介绍
2012/11/16 PHP
php生成rss类用法实例
2015/04/14 PHP
Thinkphp模板标签if和eq的区别和比较实例分析
2015/07/01 PHP
php获取字符串前几位的实例(substr返回字符串的子串用法)
2017/03/08 PHP
yii2使用gridView实现下拉列表筛选数据
2017/04/10 PHP
PHP实现mysqli批量执行多条语句的方法示例
2017/07/22 PHP
js继承 Base类的源码解析
2008/12/30 Javascript
基于jQuery的模仿新浪微博时间的组件
2011/10/04 Javascript
javascript实现yield的方法
2013/11/06 Javascript
javascript搜索框效果实现方法
2015/05/14 Javascript
jQuery 选择符详细介绍及整理
2016/12/02 Javascript
两种简单的跨域方法(jsonp、php)
2017/01/02 Javascript
基于vue实现分页/翻页组件paginator示例
2017/03/09 Javascript
微信小程序动态添加分享数据
2017/06/14 Javascript
基于input框覆盖掉数字英文的实例讲解
2017/07/21 Javascript
jQuery Layer弹出层传值到父页面的实现代码
2017/08/17 jQuery
vue超时计算的组件实例代码
2018/07/09 Javascript
vue如何进行动画的封装
2018/09/26 Javascript
Vue数据双向绑定的深入探究
2018/11/27 Javascript
Vue.js的复用组件开发流程完整记录
2018/11/29 Javascript
Python二分查找详解
2015/09/13 Python
分享一个可以生成各种进制格式IP的小工具实例代码
2017/07/28 Python
pycharm设置鼠标悬停查看方法设置
2019/07/29 Python
详解python中的index函数用法
2019/08/06 Python
pandas数据拼接的实现示例
2020/04/16 Python
Python 执行矩阵与线性代数运算
2020/08/01 Python
墨西哥运动服饰和鞋网上商店:Netshoes墨西哥
2016/07/28 全球购物
实习单位接收函
2014/01/11 职场文书
餐饮采购员岗位职责
2014/03/15 职场文书
学校领导班子四风问题整改意见
2014/10/02 职场文书
中考学习决心书
2015/02/04 职场文书
2015年毕业实习工作总结
2015/05/29 职场文书
2015秋季开学典礼演讲稿
2015/07/16 职场文书
小学作文指导之如何写人?
2019/07/08 职场文书
PHP中多字节字符串操作实例详解
2021/08/23 PHP
Sql Server之数据类型详解
2022/02/28 SQL Server