I'm trying to use fabric.js with Typescript and Webpack aside some other modules in a Laravel 5.4 application that work fine in the browser. @types/fabric ist installed and Typescript behaves correct. New to Typescript as well as Webpack i tried some variants with no success.
The problem
result.js:198 Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_1_fabric___default.a.Canvas is not a constructor
Variant A
code.ts
import fabric from "fabric";
const canvas = new fabric.Canvas('my-canvas');
result.js
var canvas = new __WEBPACK_IMPORTED_MODULE_1_fabric__default.a.Canvas('my-canvas');
WEBPACK_IMPORTED_MODULE_1_fabric__default requires WEBPACK_IMPORTED_MODULE_1_fabric which is an object with fabric as key.
const canvas = new fabric.fabric.Canvas('my-canvas');
would be working for Webpack but is not conform to type inspections.
Variant B
code.ts
import * as fabric from "fabric";
const canvas = new fabric.Canvas('my-canvas');
result.js
var canvas = new __WEBPACK_IMPORTED_MODULE_1_fabric__["Canvas"]('my-canvas');
WEBPACK_IMPORTED_MODULE_1_fabric contains an object with fabric as key so that the situation is like with variant A.
Variant C
code.ts
import {Canvas} from "fabric";
const canvas = new Canvas('my-canvas');
result.js
var canvas = new __WEBPACK_IMPORTED_MODULE_1_fabric__["Canvas"]('my-canvas');
At the end it is the same as with variant B.
excerpt of webpack.mix.js
.webpackConfig({
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [
path.resolve('app/public/js'),
path.resolve('node_modules/countable')
],
},
{
test: /\.vue$/,
loader: 'vue-loader',
exclude: [
path.resolve('resources/assets/ts/ponents')
],
options: {
loaders: {
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
}
}
},
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
}
},
]
},
plugins: [
new webpack.ProvidePlugin({
'_': 'lodash',
'$': 'jquery',
'jQuery': 'jquery',
'window.jQuery': 'jquery',
}),
new LiveReloadPlugin()
],
resolve: {
extensions: ['.js', '.ts', '.vue', '.jsx', '.tsx', '.vuex'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
}
}
The problem seem to be in Webpack and/or the babel-loader doesn't take the fabric namepace into account.
So the question is if there is any method to tell Webpack to handle this import in a way that it directly references fabric (or an imported library of that kind) or to import it into Typescript in a way that also Webpack is happy?
I'm trying to use fabric.js with Typescript and Webpack aside some other modules in a Laravel 5.4 application that work fine in the browser. @types/fabric ist installed and Typescript behaves correct. New to Typescript as well as Webpack i tried some variants with no success.
The problem
result.js:198 Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_1_fabric___default.a.Canvas is not a constructor
Variant A
code.ts
import fabric from "fabric";
const canvas = new fabric.Canvas('my-canvas');
result.js
var canvas = new __WEBPACK_IMPORTED_MODULE_1_fabric__default.a.Canvas('my-canvas');
WEBPACK_IMPORTED_MODULE_1_fabric__default requires WEBPACK_IMPORTED_MODULE_1_fabric which is an object with fabric as key.
const canvas = new fabric.fabric.Canvas('my-canvas');
would be working for Webpack but is not conform to type inspections.
Variant B
code.ts
import * as fabric from "fabric";
const canvas = new fabric.Canvas('my-canvas');
result.js
var canvas = new __WEBPACK_IMPORTED_MODULE_1_fabric__["Canvas"]('my-canvas');
WEBPACK_IMPORTED_MODULE_1_fabric contains an object with fabric as key so that the situation is like with variant A.
Variant C
code.ts
import {Canvas} from "fabric";
const canvas = new Canvas('my-canvas');
result.js
var canvas = new __WEBPACK_IMPORTED_MODULE_1_fabric__["Canvas"]('my-canvas');
At the end it is the same as with variant B.
excerpt of webpack.mix.js
.webpackConfig({
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [
path.resolve('app/public/js'),
path.resolve('node_modules/countable')
],
},
{
test: /\.vue$/,
loader: 'vue-loader',
exclude: [
path.resolve('resources/assets/ts/ponents')
],
options: {
loaders: {
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
}
}
},
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
}
},
]
},
plugins: [
new webpack.ProvidePlugin({
'_': 'lodash',
'$': 'jquery',
'jQuery': 'jquery',
'window.jQuery': 'jquery',
}),
new LiveReloadPlugin()
],
resolve: {
extensions: ['.js', '.ts', '.vue', '.jsx', '.tsx', '.vuex'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
}
}
The problem seem to be in Webpack and/or the babel-loader doesn't take the fabric namepace into account.
So the question is if there is any method to tell Webpack to handle this import in a way that it directly references fabric (or an imported library of that kind) or to import it into Typescript in a way that also Webpack is happy?
Share Improve this question asked Sep 4, 2017 at 8:14 colonelzcolonelz 811 silver badge4 bronze badges 5- what about import { fabric } from 'fabric' ? – AndreaBogazzi Commented Sep 4, 2017 at 22:39
-
Yes, i tried that but that results only in an error:
error TS2305: Module '".../node_modules/@types/fabric/index"' has no exported member 'fabric'.
– colonelz Commented Sep 7, 2017 at 10:59 - Where did you take the type definition for fabricjs? – AndreaBogazzi Commented Sep 7, 2017 at 11:09
- I used the one from @types/fabric installed them via npm and left them in the folder under node_modules/@types/fabric. – colonelz Commented Sep 7, 2017 at 21:58
- I have the exact same issue, Im using it along with a react app which has been setup using create-react-app. Any idea on how to solve the same without modifying webpack. – Viswas Menon Commented Mar 14, 2018 at 18:58
2 Answers
Reset to default 3This worked for me:
import 'fabric' ;
declare let fabric: any;
var c = new fabric.Canvas('myCanvas') ;
I'm using @types/fabric 1.5.26 on TypeScript 2.5.3 and webpack 3.5.1
The solution lied in the configuration of webpack.mix.js. The exports-loader has to be added for fabric to solve the problem. The follwoing rule were added:
rules: [
...
{
test: /fabric(\.min)?\.js$/,
use: 'exports-loader?fabric',
},
]
and fabric can be used like in variant a:
import fabric from "fabric";
const canvas = new fabric.Canvas('my-canvas');
Make sure the exports-loader is installed. I found the hint here: https://github./OfficeDev/office-ui-fabric-js/issues/258