如何獲取vue單文件自身源碼路徑
這個問題要從一個想法說起。
D2Admin 是一個開源的,前端中后臺集成方案,原先是基于 vue-cli2,大概是向 vue-cli3 過渡時,
作者老李,想在頁面右下角加個 Toggle 點(diǎn)擊,跳到當(dāng)前頁面源碼對應(yīng)的 github 頁面。
確實(shí)很實(shí)用的功能,D2Admin 的 Demo 頁面太多了,想看某個頁面的源碼,對于不熟悉項(xiàng)目目錄結(jié)構(gòu)的新手很不友好。
這些頁面統(tǒng)一為 .vue 組件,那么轉(zhuǎn)換一下:如何獲取 vue 單文件自身源碼路徑?
目前經(jīng)歷了三個方案,最終目標(biāo)是把自身路徑賦值到 this.$options.__source 上。目前方案 3 是最新的。
方案 1 :node + __filename
直接使用 node 中的 __filename 變量:
<template>
<h1>{{ $options.__source }}</h1>
</template>
<script>
export default {
mounted() {
this.$options.__source = __filename
}
}
</script>
因?yàn)?webpack 編譯時,會把源碼文件在內(nèi)部轉(zhuǎn)為 node 模塊,.vue 文件中的 script 內(nèi)容也被轉(zhuǎn)換了,
其中的 __filename 在編譯時被運(yùn)行,直接得到當(dāng)前文件自身路徑。
使用這個變量還需要在 webpack 配置中啟用 node.__filename:
/* vue.config.js */
module.exports = {
// ...
chainWebpack: config => {
// ...
config.node
.set('__dirname', true) // 同理
.set('__filename', true)
}
};
缺點(diǎn)
- 要在每個組件里手動賦值,還不能用 mixin
- __filename 得到的路徑在部分 .vue 文件下并不準(zhǔn)確,路徑可能還會帶附帶 querystring
一開始,堅(jiān)強(qiáng)的老李用這個方式,給上百個組件手動掛上了路徑,但總比手動寫死每個路徑要好
方案 2 :vue-loader + exposeFilename
在 loader 層面,其實(shí) vue-loader 提供了一個 exposeFilename 選項(xiàng),只要啟用,
就會給每個 .vue 組件帶上 this.$options.__file,上面有準(zhǔn)確的路徑。
這樣只需要改 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
})
}
};
開發(fā)環(huán)境默認(rèn)是開啟 exposeFilename 的。
此時組件內(nèi)應(yīng)該直接取 this.$options.__file,內(nèi)容大致為 src/foo/bar.vue。
缺點(diǎn)
為了安全,vue-loader 在生產(chǎn)環(huán)境將 __file 賦值為文件名,非路徑名,詳見文檔
后來得知這個方法,老李就第一時間改代碼,刪了方案 1 中的所有附加代碼,結(jié)果發(fā)現(xiàn)生產(chǎn)環(huán)境結(jié)果不一致,翻車了orz
方案 3 :loader + Custom Block
既然方案 2 不讓在生產(chǎn)環(huán)境用,那就自己寫 loader 去加上這個源碼路徑,這里采用了Custom Block。
這個方法是慢慢調(diào)試自定義的 loader 摸索出來的,先在 vue-loader 之前加自定義的 loader A,
去注入 Custom Block 代碼,再在全局加入一個針對該 Custom Block 的 loader B。
這里將方案封裝,在 chainWebpack 中調(diào)用即可:
/* 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() 不是預(yù)期的結(jié)果,這里就繞了一下
.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)
}
相關(guān)倉庫
可進(jìn)入預(yù)覽頁面查看效果,在右下角有 Toggle
github.com/d2-projects… (可能還在翻車中)
總結(jié)
目前看來,用自定義 loader 去注入代碼是最便捷的方案,不用在每個組件中手寫重復(fù)的代碼。
由于 vue-cli3 采用 chainWebpack,加上個人對 webpack 的理解更是不深,暫時采用方案 3。
以上所述是小編給大家介紹的如何獲取vue單文件自身源碼路徑詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
vue2與vue3中生命周期執(zhí)行順序的區(qū)別說明
這篇文章主要介紹了vue2與vue3中生命周期執(zhí)行順序的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
vue項(xiàng)目中使用rem,在入口文件添加內(nèi)容操作
這篇文章主要介紹了vue項(xiàng)目中使用rem,在入口文件添加內(nèi)容操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
vue.js中關(guān)于點(diǎn)擊事件方法的使用(click)
這篇文章主要介紹了vue.js中關(guān)于點(diǎn)擊事件方法的使用(click),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
vue3+elementPlus實(shí)現(xiàn)年份選擇器
這篇文章主要為大家詳細(xì)介紹了vue3如何通過elementPlus實(shí)現(xiàn)一個簡單的年份選擇器,文中的示例代碼講解詳細(xì),需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
Vue項(xiàng)目線上更新無需強(qiáng)制刷新的幾種實(shí)現(xiàn)方案(無感更新)
在 Vue 項(xiàng)目中,當(dāng)發(fā)布新版本后,用戶可能因?yàn)闉g覽器緩存而繼續(xù)使用舊版本,所以本文給大家介紹了Vue 項(xiàng)目線上更新無需強(qiáng)制刷新的幾種實(shí)現(xiàn)方案,并通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下2025-03-03
基于Vue實(shí)現(xiàn)一個textarea幽靈建議功能
不知道你有沒有發(fā)現(xiàn)Bing AI聊天有個輸入提示功能,在用戶輸入部分內(nèi)容時后面會給出灰色提示文案,用戶只要按下tab鍵就可以快速添加提示的后續(xù)內(nèi)容,我將這個功能稱為幽靈建議,接下來我將用Vue框架來實(shí)現(xiàn)這個功能,需要的朋友可以參考下2023-09-09
Laravel 如何在blade文件中使用Vue組件的示例代碼
這篇文章主要介紹了Laravel 如何在blade文件中使用Vue組件,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06

