2

I am trying to get FabricJs to work with Webpack and Electron and currently not getting it to work.

Failed to compile.

    ./~/bindings/bindings.js
    76:22-40 Critical dependency: the request of a dependency is an expression

I'm getting that when it is trying to compile the FabricJs with Webpack. Have searched in on Google and Stack Overflow and I haven't found a proper solution for it.

This is all the warnings I recieve when I run the DEV compilin:

WARNING in ./~/bindings/bindings.js 76:22-40 Critical dependency: the request of a dependency is an expression

     WARNING in ./~/bindings/bindings.js
     76:43-53 Critical dependency: the request of a dependency is an expression

 WARNING in ./~/ajv/lib/compile/index.js
 13:21-34 Critical dependency: the request of a dependency is an expression

 WARNING in ./~/ajv/lib/async.js
 96:20-33 Critical dependency: the request of a dependency is an expression

 WARNING in ./~/ajv/lib/async.js
 119:15-28 Critical dependency: the request of a dependency is an expression

In my main.js code this is exactly what is written

import Vue from 'vue'
import Electron from 'vue-electron'
import Router from 'vue-router'
import Store from 'vuex'
import {fabric} from 'fabric'

I've tried loading it like import 'fabric' or import fabric from 'fabric/dist/fabric.require' and many other ways and it always gets me the same resul.

And the webpack config file is separated in two files webpack.main.config.js and webpack.renderer.config.js

Here is the content of webpack.main.config.js

'use strict'

process.env.BABEL_ENV = 'main'

const path = require('path')
const pkg = require('./app/package.json')
const settings = require('./config.js')
const webpack = require('webpack')

console.log(pkg.dependencies)

let mainConfig = {
  entry: {
    main: path.join(__dirname, 'app/src/main/index.js')
  },
  externals: Object.keys(pkg.dependencies || {}),
  module: {
    exprContextCritical: false,
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: /camo/
      },
      {
        test: /\.json$/,
        loader: 'json-loader'
      },
      {
        test: /\.node$/,
        loader: 'node-loader'
      }
    ]
  },
  node: {
    __dirname: false,
    __filename: false
  },
  output: {
    filename: '[name].js',
    libraryTarget: 'commonjs2',
    path: path.join(__dirname, 'app/dist')
  },
  plugins: [
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ],
  resolve: {
    extensions: ['.js', '.json', '.node'],
    modules: [
      path.join(__dirname, 'app/node_modules')
    ]
  },
  target: 'electron-main'
}

module.exports = mainConfig

And this is the content of the webpack.renderer.config.js

'use strict'

process.env.BABEL_ENV = 'renderer'

const path = require('path')
const pkg = require('./app/package.json')
const settings = require('./config.js')
const webpack = require('webpack')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const AssetsPlugins = require('assets-webpack-plugin')
const assetsPluginInstance = new AssetsPlugins()

let rendererConfig = {
  devtool: '#eval-source-map',
  devServer: { overlay: true },
  entry: {
    renderer: path.join(__dirname, 'app/src/renderer/main.js')
  },
  externals: Object.keys(pkg.dependencies || {}),
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      },
      {
        test: /\.html$/,
        use: 'vue-html-loader'
      },
      {
        test: /\.js$/,
        use: 'babel-loader',
        include: [ path.resolve(__dirname, 'app/src/renderer') ],
        exclude: /node_modules/
      },
      {
            test: /\.js$/,
            loader: 'babel-loader',
            include: /camo/
      },
      {
        test: /\.json$/,
        use: 'json-loader'
      },
      {
        test: /\.node$/,
        use: 'node-loader'
      },
      {
        test: /\.vue$/,
        use: {
          loader: 'vue-loader',
          options: {
            loaders: {
              sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
              scss: 'vue-style-loader!css-loader!sass-loader'
            }
          }
        }
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          query: {
            limit: 10000,
            name: 'imgs/[name].[ext]'
          }
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          query: {
            limit: 10000,
            name: 'fonts/[name].[ext]'
          }
        }
      }
    ]
  },
  plugins: [
    assetsPluginInstance,
    new ExtractTextPlugin('styles.css'),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './app/index.ejs',
      appModules: process.env.NODE_ENV !== 'production'
        ? path.resolve(__dirname, 'app/node_modules')
        : false,
    }),
    new webpack.NoEmitOnErrorsPlugin()
  ],
  output: {
    filename: '[name].js',
    libraryTarget: 'commonjs2',
    path: path.join(__dirname, 'app/dist')
  },
  resolve: {
    alias: {
      'components': path.join(__dirname, 'app/src/renderer/components'),
      'renderer': path.join(__dirname, 'app/src/renderer')
    },
    extensions: ['.js', '.vue', '.json', '.css', '.node'],
    modules: [
      path.join(__dirname, 'app/node_modules'),
      path.join(__dirname, 'node_modules')
    ]
  },
  target: 'electron-renderer'
}


/**
 * Adjust rendererConfig for production settings
 */
if (process.env.NODE_ENV === 'production') {
  rendererConfig.devtool = ''

  rendererConfig.plugins.push(
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  )
}

module.exports = rendererConfig

2 Answers 2

3

Did you install fabric without the optional cairo dependencies (only needed/useful in node)?
npm install fabric --no-optional (see https://github.com/kangax/fabric.js/issues/2775)
My workaround ended up using script-loader which does the same thing as including fabric in a <script> tag in the browser (just that you get the benefits of webpack bundling) import "!script-loader!../static/fabricjs/fabric.js" // window.fabric is now loaded also, I didn't install fabric over npm (since that again installed the dependencies for node), but grabbed a custom build - although both should work fine.

Sign up to request clarification or add additional context in comments.

1 Comment

Installing with npm and the --no-optional flag worked for me. The import like this: import {fabric} from 'fabric'. The cairo dep does not appear to be needed if you are using this on the front-end. They do not communicate that well
1

Loading it with script-loader has finally made it work with my setup.

For people using vue + webpack + fabric is also a good idea to put the fabric call inside the mount() method on the components or Vue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.