'How to make a dynamic import in Nuxt?

In my nuxt component I want to use the ace editor:

import Ace from "ace-builds/src-noconflict/ace"

when the component is mounted I am doing the following:

this.editor = Ace.edit...

Obviously the window is not defined on the server on page reload. But unfortunately I just can't find a solution to fix this issue.

Is there a way to import a package on the mounted() hook? I already tried

const Ace = require("ace-builds/src-noconflict/ace")

But that doesn't quite seem to work. Do you have any ideas to solve this issue?

I already tried to register a plugin plugins/ace.js:

import Vue from "vue"
import Ace from "ace-builds/src-noconflict/ace"
Vue.use(Ace)

registered it in nuxt.config.js:

plugins: [
    { src: "~/plugins/ace", mode: "client" }
],

But how do I use Ace in my component now? It is still undefined...



Solution 1:[1]

Since the error was thrown during the import statement, I'd recommended using dynamic imports as explained in my other answer here.

async mounted() {
  if (process.client) {
    const Ace = await import('ace-builds/src-noconflict/ace')
    Ace.edit...
  }
},

From the official documentation: https://nuxtjs.org/docs/2.x/internals-glossary/context


EDIT: I'm not sure about Ace and it's maybe a drastic change but you may also give a look to vue-monaco which is elbow-to-elbow popularity wise (vanilla Monaco editor).

EDIT2: mounted actually only runs on the client so you could strip the process.client conditional. Meanwhile, I do let it here in case you want to run some logic in other hooks like created (which are run on both server + client). More info here.


EDIT3: not directly related to the question, but some packages expose a component which is only available on the client-side (no SSR support), in those cases you could import the component only on the client side and easily prevent any other errors.

Solution 2:[2]

Nuxt Plugin

IMHO you were on the right track with the "plugin" solution. Only mistake was the Vue.use(Ace) part. This only works for vue plugins.

The plugin file could look somewhat like that:

import Ace from 'ace-builds/src-noconflict/ace'
import Theme from 'ace-builds/src-noconflict/theme-monokai'

export default ({ app }, inject) => {
  inject('ace', {
    editor: Ace,
    theme: Theme
  })
}

Then you could use this plugin and initiate the editor in a component this way:

<template>
  <div id="editor">
    function foo(items) {
    var x = "All this is syntax highlighted";
    return x;
    }
  </div>
</template>

<script>
export default {
  data () {
    return {
      editor: {}
    }
  },
  mounted () {
    this.editor = this.$ace.editor.edit('editor')
    this.editor.setTheme(this.$ace.theme)
  }
}
</script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 kissu