這個問題要從一個想法說起。
市中網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、APP開發(fā)、成都響應式網(wǎng)站建設等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)建站成立與2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設就選創(chuàng)新互聯(lián)建站。
D2Admin 是一個開源的,前端中后臺集成方案,原先是基于 vue-cli2,大概是向 vue-cli3 過渡時,
作者老李,想在頁面右下角加個 Toggle 點擊,跳到當前頁面源碼對應的 github 頁面。
確實很實用的功能,D2Admin 的 Demo 頁面太多了,想看某個頁面的源碼,對于不熟悉項目目錄結構的新手很不友好。
這些頁面統(tǒng)一為 .vue 組件,那么轉換一下:如何獲取 vue 單文件自身源碼路徑?
目前經(jīng)歷了三個方案,最終目標是把自身路徑賦值到 this.$options.__source 上。目前方案 3 是最新的。
方案 1 :node + __filename
直接使用 node 中的 __filename 變量:
{{ $options.__source }}
因為 webpack 編譯時,會把源碼文件在內(nèi)部轉為 node 模塊,.vue 文件中的 script 內(nèi)容也被轉換了,
其中的 __filename 在編譯時被運行,直接得到當前文件自身路徑。
使用這個變量還需要在 webpack 配置中啟用 node.__filename:
/* vue.config.js */ module.exports = { // ... chainWebpack: config => { // ... config.node .set('__dirname', true) // 同理 .set('__filename', true) } };
缺點
一開始,堅強的老李用這個方式,給上百個組件手動掛上了路徑,但總比手動寫死每個路徑要好
方案 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 }) } };
開發(fā)環(huán)境默認是開啟 exposeFilename 的。
此時組件內(nèi)應該直接取 this.$options.__file,內(nèi)容大致為 src/foo/bar.vue。
缺點
為了安全,vue-loader 在生產(chǎn)環(huán)境將 __file 賦值為文件名,非路徑名,詳見文檔
后來得知這個方法,老李就第一時間改代碼,刪了方案 1 中的所有附加代碼,結果發(fā)現(xiàn)生產(chǎn)環(huán)境結果不一致,翻車了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() 不是預期的結果,這里就繞了一下 .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單文件自身源碼路徑詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對創(chuàng)新互聯(lián)網(wǎng)站的支持!