How to use EditorJS in NuxtJS project?

2.9k views Asked by At

I'm trying to use EditorJs in NuxtJs project.

Medium has an article on https://medium.com/code4mk-org/editorjs-vue-a78110c3fff8.

It works, but if I reload the page I get a "window not defined" error because the code is trying to run on the server side.

There is a package called https://github.com/ChangJoo-Park/vue-editor-js that works for NuxtJs, but it has an issue with image upload.

//I try change 

import EditorJS from '@editorjs/editorjs'

//to 
const EditorJS = require('@editorjs/editorjs')

It's works, but i got error on load tools

// ImageTool = require('@editorjs/image') // got error

Perhaps there is another way?

3

There are 3 answers

0
jtlindsey On

Here is an example of how I used it in a Nuxt.js project:

Using with Nuxt.js (2.15.x)

Tested with editor.js 2.22.x and nuxt 2.15.x. You will obviously have to expand for your needs but this is the basics.

Install modules

Install all your modules: npm i --save @editorjs/editorjs @editorjs/header

Create plugin

1. Create the following in your Nuxt project plugins/editor.js

import EditorJS from '@editorjs/editorjs';
import Header from '@editorjs/header';

export default (context, inject) => {
  const defaultOptions = {
    id: '',
    data: {},
    onChange: () => {},
  }

  const editor = (options = defaultOptions) => {
    return new EditorJS({
      placeholder: 'Let`s write an awesome story!',
      /**
       * Id of Element that should contain Editor instance
       */
      holder: options.id,
      /** 
       * Available Tools list. 
       * Pass Tool's class or Settings object for each Tool you want to use 
       */
      tools: {
        header: Header,
      },
      /**
       * Previously saved data that should be rendered
       */
      data: options.data || {},
      onChange(data) {
        // pass in function from component to run on change
        options.onChange(data)
      }
    })
  };

  inject('editor', options => editor(options));
}

2. Edit your nuxt.config.js plugins block to include it:

  plugins: [
    ...
    { src: '~/plugins/editor.js', mode: 'client' },
    ...
  ],

3. Create component components/Editor.vue

<template>
  <div id="editorjs" />
</template>

<script>
export default {
  name: 'Editor',
  props: {
    existingContent: { type: Object, default: () => {} }
  },
  data() {
    return {
      editor: null,
    }
  },
  async mounted() {
    const editorOptions = {
      id: 'editorjs',
      data: this.existingContent,
      onChange: this.onChange
    };
    this.editor = this.$editor(editorOptions);
    await this.editor.isReady;
  },
  methods: {
    async onChange() {
      try {
        const updatedData = await this.editor.save();
        console.log('Article data saved: ', updatedData)
        this.$emit('contentChanged', updatedData);
      } catch (error) {
        console.log('Saving failed: ', error)
      }
    },
  }
}
</script>

4. Create component to display editor results in components/Blog.vue

<template>
  <div>
    <template v-for="block in editorContent.blocks">
      <h1
        v-if="block.type === 'header' && block.data.level === 1"
        :key="block.id"
      >{{ block.data.text }}</h1>

      <h2
        v-if="block.type === 'header' && block.data.level === 2"
        :key="block.id"
      >{{ block.data.text }}</h2>

      <p
        v-if="block.type === 'paragraph'"
        :key="block.id"
      >{{ block.data.text }}</p>
    </template>
  </div>
</template>

<script>
export default {
  name: 'Blog',
  props: {
    editorContent: { type: Object, default: () => {} },
  }
}
</script>

4. Example using in pages/index.vue

<template>
  <div>
    <Editor
      :blog-content="editorContent"
      @contentChanged="onChange"
    />
    <Blog :editor-content="editorContent" />
  </div>
</template>

<script>
import Blog from '~/components/Blog.vue'
import Editor from '~/components/Editor.vue'
const editorContent = {
  time: 1629305722425,
  blocks: [
    {
      id: 'P0gOThWo9y',
      type: 'header',
      data: {
        text: 'Editor.js',
        level: 1,
      },
    },
    {
      id: 'YsJdcKCfHt',
      type: 'paragraph',
      data: {
        text: 'Hey. Meet the new Editor. On this page you can see it in action — try to edit this text.',
      },
    },
    {
      id: 'iIhdNHjLzc',
      type: 'header',
      data: {
        text: 'What does it mean clean data output',
        level: 2,
      },
    },
    {
      id: 'BaOtN0Tn3V',
      type: 'paragraph',
      data: {
        text: 'Classic WYSIWYG-editors produce raw HTML-markup with both content data and content appearance. On the contrary, Editor.js outputs JSON object with data of each Block. You can see an example below',
      },
    },
    {
      id: '0ReqIOJLNx',
      type: 'paragraph',
      data: {
        text: 'Given data can be used as you want: render with HTML for <code class="inline-code">Web clients</code>, render natively for <code class="inline-code">mobile apps</code>, create markup for <code class="inline-code">Facebook Instant Articles</code> or <code class="inline-code">Google AMP</code>, generate an <code class="inline-code">audio version</code> and so on.',
      },
    },
    {
      id: '7UTs8tiQqx',
      type: 'paragraph',
      data: {
        text: 'Clean data is useful to sanitize, validate and process on the backend.',
      },
    },
    {
      id: 'iFrktjRJ5I',
      type: 'paragraph',
      data: {
        text: "We have been working on this project more than three years. Several large media projects help us to test and debug the Editor, to make it's core more stable. At the same time we significantly improved the API. Now, it can be used to create any plugin for any task. Hope you enjoy. ",
      },
    },
  ],
  version: '2.22.2',
}

export default {
  components: { Editor, Blog },
  data() {
    return { editorContent }
  },
  methods: {
    onChange(data) {
      console.log('component content was changed...')
      this.editorContent = data;
    }
  }
}
</script>
0
Ilya Vo On
<template> 
   <div id="codex-editor"></div> 
</template> 

<script> 
    let EditorJS = null, ImageTool = null; 

    if (process.client) { 
        EditorJS = require('@editorjs/editorjs'); 
        ImageTool = require('@editorjs/image'); 
    } 

     export default { 
         mounted() { 
         const editor = new EditorJS({ 
         holder: 'codex-editor', 

     tools: { 
         image: { 
             class: ImageTool, 
         } 
     } 
    }); 
  } 
 } 

0
Mr.Fokuss On

@jtlindsey's answer is pretty good, but it didn't work for me. When launching the project provided by @jtlindsey, errors appeared in the terminal, here is one of them:

    Module parse failed: Unexpected token (2947:7)                                                                                  friendly-errors 12:43:42
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|       return;
|     }
>     e ?? !this.Editor.BlockSettings.opened ? (this.Editor.Toolbar.moveAndOpen(), this.Editor.BlockSettings.open()) : this.Editor.BlockSettings.close();
|   }
|   /**

I assume that this error is due to the fact that NuxtJS v2 does not understand modern ES syntax standards. My solution to this problem is to correct the syntax so that Nuxt2 can use it, as well as to extract the editorjs.mjs file from /nodemodules to plugins and then use it via import to /plugins/editor.js

import EditorJS from '@/plugins/editorjs';

You can try out a working example of EditorJS on Nuxt2 by linking my repository with GitHub