vuepress打包部署踩坑及解決
vuepress打包部署踩坑記錄
官網(wǎng)給了多種部署方案,這里我才用的是部署到github上
在你的項(xiàng)目中,創(chuàng)建一個(gè)如下的 deploy.sh 文件(請(qǐng)自行判斷去掉高亮行的注釋):
#!/usr/bin/env sh # 確保腳本拋出遇到的錯(cuò)誤 set -e # 生成靜態(tài)文件 npm run docs:build # 進(jìn)入生成的文件夾 cd docs/.vuepress/dist # 如果是發(fā)布到自定義域名 # echo 'www.example.com' > CNAME git init git add -A git commit -m 'deploy' # 如果發(fā)布到 https://<USERNAME>.github.io # git push -f git@github.com:<USERNAME>/<USERNAME>.github.io.git main # 如果發(fā)布到 https://<USERNAME>.github.io/<REPO> /**這個(gè)地方換成自己的github地址和倉(cāng)庫(kù)地址**/ git push -f git@github.com:FightingN/vue-common-vuepress.git master:gh-pages cd -
然后需要注意的是 .vuepress/config.js文件的base需要修改一下
base: '/vue-common-vuepress/',
然后運(yùn)行npm run deploy就可以正常打包到github托管中了
vuepress打包報(bào)錯(cuò):error Error rendering /:
問(wèn)題
使用vuepress寫文檔網(wǎng)站,為了實(shí)現(xiàn)element-ui類似的組件預(yù)覽效果,項(xiàng)目里面將ant-design-vue和基于ant-design-vue的自己封裝的組件引入項(xiàng)目中,開(kāi)發(fā)環(huán)境能正常運(yùn)行。當(dāng)運(yùn)行Build打包后,報(bào)錯(cuò):error Error rendering /:

方案1
經(jīng)查詢vuepress github issuse 得到的答案是,vuepress是服務(wù)端渲染的,瀏覽器的 API 訪問(wèn)限制。在頁(yè)面加載第三方組件的時(shí)候,可能出現(xiàn)找不到的情況,建議在當(dāng)前頁(yè)面使用時(shí)再引入。

當(dāng)然,如果不需要組件預(yù)覽效果,及:::demo標(biāo)志,就不會(huì)報(bào)錯(cuò)。需要該效果時(shí),按照官網(wǎng)的做法,使用component標(biāo)簽,在需要的md 代碼塊里面動(dòng)態(tài)加載組件,可以解決該問(wèn)題
mounted(){
import("my-component").then(myComponent=>{
console.log("myComponent", myComponent)
this.dynamicComponent = myComponent.Tree
})
},
當(dāng)然還有一種方法就是在mounted里面import組件并且注冊(cè)組件,template部分照常使用之前的標(biāo)簽
<template>
<my-tree/>
</template>
<script>
import Vue from "vue"
export default {
mounted(){
import("my-component").then(myComponent=>{
console.log("myComponent", myComponent)
Vue.component("myTree",myComponent.Tree)
})
}
}
</script>
然而運(yùn)行后,報(bào)錯(cuò)my-tree沒(méi)有注冊(cè)。
Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the “name” option.
found in
方案2
方案1,問(wèn)題看是解決了,沒(méi)有報(bào)錯(cuò)了,但是。這不是我們想要的。
本質(zhì)需求是實(shí)現(xiàn)組件庫(kù)的組件預(yù)覽效果,并且能復(fù)制代碼,方案1能預(yù)覽,但是代碼都變成了component標(biāo)簽,不符合需求。
接下來(lái)我們想排查下是什么組件影響了打包:
采用本地建測(cè)試倉(cāng)庫(kù),本地建測(cè)試組件庫(kù),本地建測(cè)試文檔項(xiàng)目,逐個(gè)移植原組件庫(kù)的組件到測(cè)試組件庫(kù)中,發(fā)布到測(cè)試倉(cāng)庫(kù)后,更新測(cè)試文檔,然后執(zhí)行本地預(yù)覽和打包命令。最終找出影響打包的組件有dialog,uploadAvatar,preview,cropper-img等組件。這些組件的共同點(diǎn)就是都直接或間接用到了document操作dom,還有其他window的方法,或者bom的方法事件,或者在組件內(nèi)注冊(cè)第三方組件,如本項(xiàng)目中就用的atob,btoa,這個(gè)也是造成出現(xiàn)該錯(cuò)誤的原因之一。經(jīng)在upoadAvatar去掉document得到驗(yàn)證。目前除了這幾個(gè)組件,其他均可以實(shí)現(xiàn)組件預(yù)覽效果。但是這幾個(gè)組件只要引入就報(bào)錯(cuò),也影響了全局。
最終解決
知道了問(wèn)題所在,結(jié)合上面的思路,總之的一點(diǎn)就是想要用window或bom方法事件,一定要在mounted后執(zhí)行。這里來(lái)一個(gè)一個(gè)看。首先看dialog組件,之所以會(huì)報(bào)錯(cuò)就是dialog組件在created生命周期的時(shí)候用了document(下面只展示關(guān)鍵代碼,多余的代碼略)
import { VNode } from "vue"
import { Component, Prop, Vue, Watch } from "vue-property-decorator"
import { dialogConfig } from "./type"
export default class Dialog extends Vue {
created() {
this.dialogInit()
this.getWindowSize()
}
/**
* 彈窗初始化
* @private
*/
private dialogInit():void {
this.id = "lc-dialog" + (Math.random() * 1000000 + new Date().getTime()).toString(16).split(".")[0]
this.$nextTick(() => {
const dialogDom:any = document.getElementById(that.id)
if (!dialogDom) {
return
}
this.dialogDom = dialogDom
this.headerDom = dialogDom.querySelector(".ant-modal-header")
this.footerDom = dialogDom.querySelector(".ant-modal-footer")
})
}
/**
* 獲取窗口尺寸
* @private
*/
private getWindowSize():void {
const that = this as any
this.windowSize = {
windowWidth: document.documentElement.clientWidth,
windowHeight: document.documentElement.clientHeight
}
// // console.log(that.dialogScreen)
// // console.log(that.isScreen)
window.onresize = () => {
if (this.dialogScreen && this.isScreen) {
clearTimeout(this.debounceTimeOut)
this.debounceTimeOut = setTimeout(() => {
this.windowSize = {
windowWidth: document.documentElement.clientWidth,
windowHeight: document.documentElement.clientHeight
}
}, 300)
}
}
}
render (h:any):VNode {
...
}
}
那這里就很簡(jiǎn)單,將created改成mounted就行
再來(lái)看看圖片裁剪組件,之前的代碼是
<!--圖片裁剪-->
<template>
<lc-dialog
:title="title"
:visible.sync="visible"
:width="800"
:footer="null"
ref="cropperModal"
:before-close="beforeClose"
:z-index="zIndex"
>
<vue-cropper
ref="cropper"
:img="img"
:info="true"
:auto-crop="options.autoCrop"
:output-type="config.outputType || (config.originFile ? config.originFile.type : '')"
:auto-crop-width="options.autoCropWidth"
:auto-crop-height="options.autoCropHeight"
:fixed-box="options.fixedBox"
@real-time="realTime"
>
</vue-cropper>
</lc-dialog>
</template>
<script>
import Vue from "vue"
import VueCropper from "vue-cropper"
import { getZIndexByDiv } from "../../utils/lc-methods"
Vue.use(VueCropper)
export default {
name: "CropperImg",
...
}
</script>
這里需要解決的是vue-cropper組件的按需引入問(wèn)題。按照vue-press的思路,可以使用動(dòng)態(tài)import,于是開(kāi)始嘗試如下:
<!--圖片裁剪-->
<template>
<lc-dialog
:title="title"
:visible.sync="visible"
:width="800"
:footer="null"
ref="cropperModal"
:before-close="beforeClose"
:z-index="zIndex"
>
<component
v-if="component"
:is="component"
ref="cropper"
:img="img"
:info="true"
:auto-crop="options.autoCrop"
:output-type="config.outputType || (config.originFile ? config.originFile.type : '')"
:auto-crop-width="options.autoCropWidth"
:auto-crop-height="options.autoCropHeight"
:fixed-box="options.fixedBox"
@real-time="realTime"
/>
</lc-dialog>
</template>
<script>
import { getZIndexByDiv } from "../../utils/lc-methods"
export default {
name: "CropperImg",
mounted() {
import("vue-cropper").then(VueCropperModule => {
this.component = VueCropperModule.VueCropper
}
},
...
}
</script>
然而運(yùn)行后發(fā)現(xiàn),沒(méi)有生效。于是將import(“vue-cropper”).catch打印發(fā)現(xiàn)竟然報(bào)錯(cuò)了。vuepress是走node服務(wù)渲染模式,也可能和nodejs 服務(wù)端渲染不支持import有關(guān),于是改成require引入,如下
<!--圖片裁剪-->
<template>
<lc-dialog
:title="title"
:visible.sync="visible"
:width="800"
:footer="null"
ref="cropperModal"
:before-close="beforeClose"
:z-index="zIndex"
>
<component
v-if="component"
:is="component"
ref="cropper"
:img="img"
:info="true"
:auto-crop="options.autoCrop"
:output-type="config.outputType || (config.originFile ? config.originFile.type : '')"
:auto-crop-width="options.autoCropWidth"
:auto-crop-height="options.autoCropHeight"
:fixed-box="options.fixedBox"
@real-time="realTime"
/>
</lc-dialog>
</template>
<script>
import { getZIndexByDiv } from "../../utils/lc-methods"
export default {
name: "CropperImg",
mounted() {
const VueCropperModule = require("vue-cropper")
// console.log("VueCropperModule", VueCropperModule)
this.component = VueCropperModule.VueCropper
},
...
}
</script>
結(jié)果成功,引入該組件后,也不會(huì)再報(bào)錯(cuò)error Error rendering /:
然后看看頭像上傳組件,這個(gè)也比較坑。這個(gè)組件mounted沒(méi)有document,也沒(méi)引入第三方組件。無(wú)奈,只有使用注釋大法逐步查找,最后確定是組件內(nèi)部引入壓縮圖片的方法造成
import { compressImageFun } from "../../utils/img-method"
發(fā)現(xiàn)只要組件引入了該方法,不管是否使用,都會(huì)報(bào)錯(cuò),而注釋該方法就萬(wàn)事大吉。
于是取查找compressImageFun相關(guān),開(kāi)始因?yàn)闊o(wú)頭緒,同樣只能使用注釋大法,最后查到罪魁禍?zhǔn)资莂tob,btoa函數(shù)。這樣那么解決辦法和引入第三方組件類似。compressImageFun里面不需要?jiǎng)?,改引入的地方就行,如?/p>
export default {
name: "UploadAvatar",
data () {
return {
compressImageFun: null, // 壓縮函數(shù) 注意這里因?yàn)闊o(wú)法直接使用compressImageFun,所以需要存在data中使用
}
},
mounted() {
const imgMethod = require("../../utils/img-method")
this.compressImageFun = imgMethod.compressImageFun
},
methods: {
/**
* 上傳之前
* @param file
* @returns {boolean}
*/
async beforeUpload (file) {
return new Promise(async (resolve, reject) => {
...省略若干代碼
if (!this.noCompress) {
newCompressFile = await this.compressImageFun({ file: cropperFile || file })
cropperFile = newCompressFile.data
}
...
})
},
}
至此,該錯(cuò)誤被攻克?。。?/p>
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue.js組件vue-waterfall-easy實(shí)現(xiàn)瀑布流效果
這篇文章主要為大家詳細(xì)介紹了vue.js實(shí)現(xiàn)瀑布流之vue-waterfall-easy的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Element InfiniteScroll無(wú)限滾動(dòng)的具體使用方法
這篇文章主要介紹了Element InfiniteScroll無(wú)限滾動(dòng)的具體使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Vue 前端實(shí)現(xiàn)登陸攔截及axios 攔截器的使用
這篇文章主要介紹了Vue 前端實(shí)現(xiàn)登陸攔截及axios 攔截器的使用,通過(guò)這個(gè)項(xiàng)目學(xué)習(xí)如何實(shí)現(xiàn)一個(gè)前端項(xiàng)目中所需要的 登錄及攔截、登出、token失效的攔截及對(duì)應(yīng) axios 攔截器的使用。需要的朋友可以參考下2019-07-07
Vue3中注冊(cè)全局的組件,并在TS中添加全局組件提示方式
這篇文章主要介紹了Vue3中注冊(cè)全局的組件,并在TS中添加全局組件提示方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
Vue如何動(dòng)態(tài)修改el-table的某列數(shù)據(jù)
這篇文章主要介紹了Vue如何動(dòng)態(tài)修改el-table的某列數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
Vue子組件調(diào)用父組件事件的3種方法實(shí)例
大家在做vue開(kāi)發(fā)過(guò)程中經(jīng)常遇到父組件需要調(diào)用子組件方法或者子組件需要調(diào)用父組件的方法的情況,這篇文章主要給大家介紹了關(guān)于Vue子組件調(diào)用父組件事件的3種方法,需要的朋友可以參考下2024-01-01
如何監(jiān)聽(tīng)Vue項(xiàng)目報(bào)錯(cuò)的4種方式?
本文主要介紹了如何監(jiān)聽(tīng)Vue項(xiàng)目報(bào)錯(cuò)的4種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
手把手教你vue-cli單頁(yè)到多頁(yè)應(yīng)用的方法
本篇文章主要介紹了手把手教你vue-cli單頁(yè)到多頁(yè)應(yīng)用的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05

