1、问题
使用自己写的一个UI库,然后利用VuePress编写官网文档,由于是第一次使用该框架,所以遇到一些问题,在这里记录下自己所踩过的坑。
使用npm run docs:dev编写完文档后,需要运行npm run docs:build将其build打包,然后发布到服务器上。然而在build的过程中,报了如下的错误:
Reason: ReferenceError: window is not defined
error Error rendering /components/button-test.html: false
undefined
Error: render function or template not defined in component: button-demo1
at normalizeRender (E:\CodeNote\Vue.js\code\yued\node_modules\vue-server-renderer\build.dev.js:8262:13)
at renderComponentInner (E:\CodeNote\Vue.js\code\yued\node_modules\vue-server-renderer\build.dev.js:8412:3)
at renderComponent (E:\CodeNote\Vue.js\code\yued\node_modules\vue-server-renderer\build.dev.js:8383:5)
at resolve (E:\CodeNote\Vue.js\code\yued\node_modules\vue-server-renderer\build.dev.js:8451:9)
意思就是vuepress在引入外部组件build报错window is not defined
2、原因分析
上网google了一圈,大概是由于浏览器的API访问限制导致,因为在build的过程中,所有的页面在生成静态HTML时都需要通过Node.js服务端渲染,而Node.js中没有window对象,这时候访问浏览器/DOM中的API自然会报错。
因此需要确保在beforeMount或者mounted访问浏览器/DOM的API。
3、解决方法
1、利用vuepress官网给出的方法<ClientOnly>
可以将组件包裹在内置的组件<ClientOnly>中:
<ClientOnly>
<NonSSRFriendlyComponent/>
</ClientOnly>
请注意,这并不能解决一些组件或库在导入时就试图访问浏览器 API 的问题 —— 如果需要使用这样的组件或库,你需要在合适的生命周期钩子中动态导入它们。
2、动态组件(动态导入)
<template>
<component v-if="dynamicComponent" :is="dynamicComponent"></component>
</template>
<script>
export default {
data() {
return {
dynamicComponent: null
}
},
mounted () {
import('./lib-that-access-window-on-import').then(module => {
this.dynamicComponent = module.default
})
}
}
</script>
这种方式也能解决问题,但是当组件文档多的时候,每次都要在mounted处理,就会很麻烦。而且可以在enhanceApp.js中一次性导入,不需要按需引入。
3、利用Mixin
组件库的引入可以放在enhanceApp.js里面,在这里使用Mixin来处理。
export default ({ Vue, options, router, siteData }) => {
Vue.use(Element);
Vue.mixin({
mounted() {
import('yued-test').then(function (m) {
Vue.component('y-button', m.YButton)
})
},
})
};
目前只想到这三种解决方法,应该还存在其他更好的解决方法。