VuePress window document is not defined

Posted May 24, 20203 min read

Foreword

Recently, I am building a vue component library(this also has a lot of stories to tell ...). After building the wheel, you need to write the component documentation. I chose vuepress , If you need a code demonstration in the documentation, you will naturally need to introduce a component library. After the component library is introduced, there is no problem in writing the document for normal use, but it is in trouble when building ...

problem

  • Question one

    ReferenceError:document is not defined

    The reason for this problem is that when I wrote the vue component, I introduced a style file in the .vue file, which looks like this:

    <style lang = "less">
      @import '../style/content.less';
    </style>
    Copy code

    This should be familiar to everyone, and the normal introduction of styles, but the problem is that after the component library code is compiled, document.querySelectory() is used for style processing, and all pages of vuepress need to pass Node.js when generating static HTML Server-side rendering, there is no document object in Node.js environment. At this time, accessing the API in the browser/DOM will naturally report an error.

    Local development is no problem, but build will be wrong

  • Question 2

    window is not defined

    This problem also occurs because the window object is used when writing the component, and there is no window object in Node.js.

solve

  • first round

    The official solution given by vuepress is to use vue's dynamic components ,

    <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>
    Copy code

    Check the Browser API access restrictions

    This method can solve the problem, but it is very troublesome. I think I have to write more than a dozen component documents. I have to do this every time I write a demo. If I encounter a complicated example, several components are used in a demo. Isn't it troublesome, not elegant enough, not elegant enough.

    And when writing the documentation, the component library can be completely imported in one time in enhanceApp.js, no need to import on demand, such as:

    import Element from 'element-ui'
    
    export default({Vue, options, router, siteData}) => {
        Vue.use(Element);
    };
    Copy code
  • second round

    In fact, the first solution above has provided us with ideas to access the API to access the browser/DOM in beforeMount or mounted.

    But according to our needs, we can no longer go to mounted in the demo component to deal with this problem separately, then we look back at enhanceApp.js, the introduction of the component library can be put here, use mixin here deal with.

    Because it is Node.js server-side rendering, the first thought of using require:

    import Element from 'element-ui'
    
    export default({Vue, options, router, siteData}) => {
        Vue.use(Element);
        Vue.mixin({
            mounted() {
                var WisdomUI = require('wisdom-ui')
                Vue.use(WisdomUI)
            },
        })
    };
    Copy code
    • build by
    • Local operation, component loading failed

    Big head, you should use ES module:

    `` `
    import Element from 'element-ui'

    export default({Vue, options, router, siteData}) => {
    Vue.use(Element);
    Vue.mixin({

       mounted() {
           import('wisdom-ui'). then(function(m) {
               Vue.use(m.default)
           })
       },

    })
    };
    Copy code
    `` `

    • No problem running locally
    • build is normal

    problem solved.

Why can't you use require to load the component library, you can look at here

Original