MarioChase MarioChase - 8 months ago 193
Javascript Question

FabricJs, Webpack not compiling - Critical dependency

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

Answer Source

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.