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) }) }, }) };
目前只想到这三种解决方法,应该还存在其他更好的解决方法。