vueup / vue-quill

Rich Text Editor Component for Vue 3.
https://vueup.github.io/vue-quill/
MIT License
1.05k stars 250 forks source link

Can't Import plugin #5

Closed narsiliko closed 3 years ago

narsiliko commented 3 years ago

I have an error when I'm trying to import the plugin onto the project.

import QuillEditor from '@vueup/vue-quill
Uncaught Error: Module parse failed: Unexpected token (8:215655)
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
import QuillEditor from '@vueup/vue-quill/dist/vue-quill.es'

or

import QuillEditor from '@vueup/vue-quill/dist/vue-quill.cjs'
Uncaught Error: Module parse failed: Unexpected token (11541:43)
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
|                     editor.value.classList.remove("ql-snow");
|                 // Fix clicking the quill toolbar is detected as blur event
>                 quill.getModule("toolbar")?.container.addEventListener("mousedown", (e) => {
|                     e.preventDefault();
|                 });
    at Object../node_modules/@vueup/vue-quill/dist/vue-quill.es.js (index.esm.js:741)

and same type of errors when importing other modules

My package.json

{
  "name": "___",
  "version": "1.1.0",
  "description": "___",
  "private": true,
  "loglevel": "silent",
  "scripts": {
    "clean": "rimraf public",
    "dev": "cross-env NODE_ENV=development webpack",
    "start": "cross-env NODE_ENV=development webpack-dev-server",
    "build": "npm run clean -s && cross-env NODE_ENV=production webpack"
  },
  "keywords": [
    "scss",
    "pug",
    "babel"
  ],
  "author": "___",
  "license": "ISC",
  "browserslist": [
    "last 2 version",
    "> 1%",
    "not dead"
  ],
  "devDependencies": {
    "@babel/core": "7.6.4",
    "@babel/plugin-proposal-class-properties": "^7.8.3",
    "@babel/plugin-proposal-optional-chaining": "^7.10.4",
    "@babel/preset-env": "^7.12.11",
    "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
    "@vue/babel-plugin-jsx": "^1.0.0",
    "@vue/babel-preset-jsx": "^1.1.2",
    "@vue/compiler-sfc": "^3.0.5",
    "babel-eslint": "10.0.2",
    "babel-loader": "8.0.6",
    "copy-webpack-plugin": "^6.4.1",
    "cross-env": "6.0.3",
    "css-loader": "3.2.0",
    "dotenv-webpack": "^2.0.0",
    "eslint": "^7.18.0",
    "eslint-plugin-babel": "5.3.0",
    "eslint-webpack-plugin": "^2.4.2",
    "file-loader": "4.2.0",
    "html-beautify-webpack-plugin": "^1.0.5",
    "html-loader": "0.5.5",
    "html-webpack-harddisk-plugin": "1.0.1",
    "html-webpack-plugin": "3.2.0",
    "mini-css-extract-plugin": "0.8.0",
    "node-sass": "^4.14.1",
    "node-sass-json-importer": "4.1.0",
    "optimize-css-assets-webpack-plugin": "5.0.3",
    "path": "0.12.7",
    "pug": "2.0.4",
    "pug-html-loader": "1.1.5",
    "pug-loader": "2.4.0",
    "raw-loader": "3.1.0",
    "rimraf": "3.0.0",
    "sass-loader": "^8.0.2",
    "svg-url-loader": "^7.1.1",
    "terser-webpack-plugin": "^4.1.0",
    "vue-loader": "^16.0.0-rc.1",
    "vue-template-compiler": "^2.6.12",
    "webpack": "4.41.2",
    "webpack-bundle-analyzer": "^4.3.0",
    "webpack-cli": "3.3.9",
    "webpack-dev-server": "^3.11.2",
    "write-file-webpack-plugin": "^4.5.1"
  },
  "dependencies": {
    "@glidejs/glide": "^3.4.1",
    "@staaky/fresco": "^2.3.1",
    "@vueform/multiselect": "^1.3.5",
    "@vuelidate/core": "^2.0.0-alpha.8",
    "@vuelidate/validators": "^2.0.0-alpha.5",
    "@vueup/vue-quill": "^1.0.0-alpha.6",
    "@yaireo/tagify": "^3.6.10",
    "anchorme": "^2.1.2",
    "axios": "^0.21.1",
    "bootstrap-4-grid": "^3.0.0",
    "choices.js": "^9.0.1",
    "core-js": "^3.8.3",
    "jquery": "^3.5.0",
    "lodash": "^4.17.20",
    "mobile-device-detect": "^0.4.3",
    "normalize.css": "^8.0.1",
    "pristinejs": "^0.1.6",
    "quill": "^1.3.7",
    "regenerator-runtime": "^0.13.7",
    "sass-mq": "5.0.1",
    "selectric": "^1.13.0",
    "tail.datetime": "^0.4.13",
    "tingle.js": "^0.15.3",
    "uuid": "^8.3.1",
    "v-click-outside": "^3.0.1",
    "vue": "^3.0.5",
    "vue-final-modal": "^1.8.4",
    "vue-native-websocket-vue3": "^3.0.2",
    "vue-upload-component": "^3.0.47",
    "vuex": "^4.0.0-rc.2",
    "vuex-map-fields": "^1.4.1"
  }
}

My Webpack configuration

// System
const webpack = require('webpack')
const fs = require('fs')
const path = require('path')

// Common
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { VueLoaderPlugin } = require("vue-loader")

// Development
const address = require('ip').address
const WriteFileWebpackPlugin = require('write-file-webpack-plugin')
// const ESLintPlugin = require('eslint-webpack-plugin')
const Dotenv = require('dotenv-webpack')

// Production
const HtmlBeautifyPlugin = require('html-beautify-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

// User
const paths = require('./webpack/paths')
const helpers = require('./webpack/helpers')

const pugTemplates = [];
const srcll = fs.readdirSync(paths.dirSrcPug);
srcll.forEach(s => s.endsWith('.pug') && pugTemplates.push(s));

const webpackConfig = {
  mode: process.env.NODE_ENV,
  entry: {
    main: paths.dirSrcJs + '/app.js',
    vue: paths.dirSrcJs + '/vue/index.js'
  },
  output: {
    path: paths.dirDist,
    filename: 'js/[name].bundle.js'
  },
  resolve: {
    alias: {
      '#root': paths.dirSrcJs,
      '#vue': paths.dirSrcJs + '/vue',
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules)/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'entry',
                    corejs: "3.8"
                  }
                ],
                '@vue/babel-preset-jsx'
              ],
              plugins: [
                ['@babel/plugin-proposal-class-properties', { 'loose': true }],
                ['@babel/plugin-proposal-optional-chaining'],
                ['@vue/babel-plugin-jsx'],
                // ['eslint-plugin-babel'],
              ]
            }
          }
        ]
      },
      {
        test: /\.css$/,
        use: helpers.styleLoaders([], process.env.NODE_ENV)
      },
      {
        test: /\.scss$/,
        use: helpers.styleLoaders([{
          loader: 'sass-loader',
          options: {
            sourceMap: process.env.NODE_ENV === 'development' ? true : false,
          },
        }], process.env.NODE_ENV)
      },
      {
        test: /\.pug$/,
        use: ['raw-loader', 'pug-html-loader']
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.svg$/,
        loader: 'svg-url-loader'
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false,
    }),
    ...pugTemplates.map(templateName => new HtmlWebpackPlugin({
      inject: true,
      template: `./src/pug/${templateName}`,
      filename: path.join(paths.dirDist, templateName.replace('.pug', '.html')),
      minify: false,
      alwaysWriteToDisk: true,
    })),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    }),
    new CopyWebpackPlugin({
      patterns: [
        { from:'src/assets', to:'assets' },
      ]
    }),
    new VueLoaderPlugin(),
  ],
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
}

if (process.env.NODE_ENV === 'development') {
  // console.log(path.join(paths.dirSrc, '/**/*.js'))
  // console.log(paths.rootPath)
  webpackConfig.devtool = 'source-map'
  webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin())
  webpackConfig.plugins.push(new Dotenv({
    path: '.env.dev',
    systemvars: true,
  }))
  webpackConfig.plugins.push(new WriteFileWebpackPlugin())
  // webpackConfig.plugins.push(new ESLintPlugin())
  webpackConfig.devServer = {
    compress: true,
    quiet: true,
    stats: {
      assets: false,
      children: false,
      chunks: false,
      chunkModules: false,
      colors: true,
      entrypoints: false,
      hash: false,
      modules: false,
      timings: false,
      version: false,
    },
    hot: true,
    lazy: false,
    host: address(),
    port: 3000,
    clientLogLevel: 'error',
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    open: true
  }
}

if (process.env.NODE_ENV === 'production') {
  webpackConfig.plugins.push(new HtmlBeautifyPlugin({
    config: {
      html: {
        end_with_newline: false,
        indent_size: 2,
        indent_with_tabs: false,
        indent_inner_html: false,
        preserve_newlines: false,
        wrap_line_length: 0,
        inline: [],
        unformatted: [],
      }
    },
  }))
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
  webpackConfig.optimization.minimizer = [
    new TerserPlugin(),
    new OptimizeCSSAssetsPlugin()
  ]
}

module.exports = webpackConfig
luthfimasruri commented 3 years ago

This error happens because webpack@4.x.x didn't support ES2020 yet, in this case, optional chaining, it should be ok if you use webpack@5.x.x

Fixed in ^1.0.0-alpha.10 or latest alpha version:

npm i @vueup/vue-quill@1.0.0-alpha.10

and import it as usual

import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { QuillEditor } from "@vueup/vue-quill";

Warning: for now on, VueQuill didn't support export default, to make it consistent between es-module and commonjs

use named import instead:

// commonjs
const { QuillEditor } = require("@vueup/vue-quill");
// es
import { QuillEditor } from "@vueup/vue-quill";
narsiliko commented 3 years ago

This error happens because webpack@4.x.x didn't support ES2020 yet, in this case, optional chaining, it should be ok if you use webpack@5.x.x

Fixed in ^1.0.0-alpha.10 or latest alpha version:

npm i @vueup/vue-quill@1.0.0-alpha.10

and import it as usual

import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { QuillEditor } from "@vueup/vue-quill";

Warning: for now on, VueQuill didn't support export default, to make it consistent between es-module and commonjs

use named import instead:

// commonjs
const { QuillEditor } = require("@vueup/vue-quill");
// es
import { QuillEditor } from "@vueup/vue-quill";

After update to version ^1.0.0-alpha.10 I tried to import plugin this way

import { QuillEditor } from '@vueup/vue-quill'

but got an error

Uncaught Error: Module build failed: Error: ENOENT: no such file or directory

If I import plugin this way

import { QuillEditor } from '@vueup/vue-quill/dist/vue-quill.esm-bundler'

I getting this warns

runtime-core.esm-bundler.js:38 [Vue warn]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.

[Vue warn]: onBeforeUnmount is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.

[Vue warn]: Missing ref owner context. ref cannot be used on hoisted vnodes. A vnode with ref must be created inside the render function. 
  at <QuillEditor theme="snow" toolbar="minimal" > 
  at <InputRichText> 
  at <InputBlock> 
  at <New3 key=2 > 
  at <New>

and seeing just rectangle without toolbar and text field instead of editor I can`t interact with.

luthfimasruri commented 3 years ago

Hmm, I'm not sure what's the problem, without knowing the entire setup. Yet, can you share your source code?

narsiliko commented 3 years ago

Hmm, I'm not sure what's the problem, without knowing the entire setup. Yet, can you share your source code?

Yes, here is the code of the component where I`m using plugin

<template>
  <div 
    class="form-field"
    :class="[
      {
        'not-empty': modelValue?.toString().length > 0,
        'form-field--disabled': disabled,
        'form-field--requesting': requesting,
        'form-field--success': success,
        'form-field--error': typeof error === 'string' && error?.length > 0,
      },
      fieldClass
    ]"
  >
    <div class="input textarea" :style="{ height: height }">
      <quill-editor
        theme="snow"
        toolbar="minimal"
      >
      </quill-editor>
      <!-- <textarea
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"
        class="textarea__textarea"
        :class="{ 'not-empty': modelValue?.toString().length > 0 }"
        v-bind="$attrs"
      />
      <label class="textarea__label" v-html="label" :class="{ 'not-empty': modelValue?.toString().length > 0 }"></label> -->
    </div>
  </div>
</template>

<script type="text/javascript">
import { QuillEditor } from '@vueup/vue-quill/dist/vue-quill.esm-bundler'
import '@vueup/vue-quill/dist/vue-quill.snow.css'

export default {
  name: "input-rich-text",
  components: {
    QuillEditor
  },
  inheritAttrs: false,
  props: {
    modelValue: String,
    value: String,
    label: String,
    height: String,
    error: String,
    fieldClass: String,
    disabled: {
      type: Boolean,
      default: false,
    },
    requesting: {
      type: Boolean,
      default: false
    },
    success: {
      type: Boolean,
      default: false
    },
    error: {
      type: String,
      default: ''
    },
  },
  emits: ['update:modelValue'],
}
</script>
luthfimasruri commented 3 years ago

I have tried the code and worked as expected, clone this repo for the source code: https://github.com/vueup/vue-quill-webpack-test.git

luthfimasruri commented 3 years ago

On CodeSandbox:

https://codesandbox.io/s/vue-quill-text-editor-ms2hv

narsiliko commented 3 years ago

I have tried the code and worked as expected, clone this repo for the source code: https://github.com/vueup/vue-quill-webpack-test.git

Yes, in your environment plugin works correctly. But I have different env with webpack, vue-loader, etc. On my env I still have warnings and blank rectangle without interface.

luthfimasruri commented 3 years ago

I don't know if it's work and fits your need or not, but you can import QuillEditor using defineAsyncComponent():

import { defineAsyncComponent } from 'vue';
const QuillEditor = defineAsyncComponent(() =>
  import("@vueup/vue-quill").then((VueQuill) => VueQuill.QuillEditor)
)
narsiliko commented 3 years ago

I don't know if it's work and fits your need or not, but you can import QuillEditor using defineAsyncComponent():

import { defineAsyncComponent } from 'vue';
const QuillEditor = defineAsyncComponent(() =>
  import("@vueup/vue-quill").then((VueQuill) => VueQuill.QuillEditor)
)

Unfortunately, this didn`t help

luthfimasruri commented 3 years ago

It seems that the problem is in your environment setup, I'm unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close the issue for now. Please don't hesitate to comment on the issue if you have any more information for us; we will reopen it right away! Thanks for your contribution.