I'm trying to create a javascript bundle with JSPM that includes fabric.js version 2. Alas, performing jspm bundle fails.
$ jspm bundle src/main --minify --inject
Building the bundle tree for src/main...
err Error on fetch for @empty/lib/jsdom/living/generated/utils.js at file:///Users/dkoerner/projects/JSPMFabricTestCase/@empty/lib/jsdom/living/generated/utils.js
Loading npm:fabric@2.0.0-rc.4/dist/fabric.js
Loading npm:fabric@2.0.0-rc.4.js
Loading src/bootstrap.js
Loading src/main.js
Error: ENOENT: no such file or directory, open '/Users/dkoerner/projects/JSPMFabricTestCase/@empty/lib/jsdom/living/generated/utils.js'
I have created a test project (https://github.com/dkoerner85/JSPMFabricTestCase) following the jspm and fabric examples and verified that bundle creation works with the current fabric stable release v1.7.22. Raising the version to the release candidate v2.0.0-rc4 however breaks bundling.
I am fairly new to javascript app development and hence do not understand the reason why this fails and how to repair it. I am grateful for any pointers or explanation.
npm: v5.5.1 node: v8.9.3
Add an override section to your project's package.json
:
"overrides": {
"npm:fabric@2.0.0-rc.4": {
"map": {
"canvas": "@empty",
"fs": "@empty",
"jsdom/lib/jsdom/living/generated/utils": "@empty",
"jsdom/lib/jsdom/utils": "@empty",
"jsdom": "@empty",
"http": "@empty",
"https": "@empty",
"xmldom": "@empty",
"url": "@empty"
}
}
}
After reading about jspm and systemJS, I have found a solution to this problem. The critical code is in the fabric.js and package.json files of the fabric package.
dist/fabric.js
...
fabric.document = require('jsdom').jsdom(decodeURIComponent('%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E'),{ features: {FetchExternalResources: ['img']}});
fabric.jsdomImplForWrapper = require('jsdom/lib/jsdom/living/generated/utils').implForWrapper;
fabric.nodeCanvas = require('jsdom/lib/jsdom/utils').Canvas;
fabric.window = fabric.document.defaultView;
DOMParser = require('xmldom').DOMParser;
...
package.json
...
"browser" : {
"canvas": false,
"fs": false,
"jsdom": false,
"jsdom/lib/jsdom/living/generated/utils": false,
"jsdom/lib/jsdom/utils": false,
"http": false,
"https": false,
"xmldom": false,
"url": false
},
...
Now, when installing the package with jspm install npm:fabric@2.0.0-rc.4
, jspm will modify the require statements, resulting in the following code:
jspm_packages/npm/fabric@2.0.0-rc.4/dist/fabric.js
...
fabric.document = require('@empty').jsdom(decodeURIComponent('%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E'), {features: {FetchExternalResources: ['img']}});
fabric.jsdomImplForWrapper = require('@empty/lib/jsdom/living/generated/utils').implForWrapper;
fabric.nodeCanvas = require('@empty/lib/jsdom/utils').Canvas;
fabric.window = fabric.document.defaultView;
DOMParser = require('@empty').DOMParser;
...
When trying to create a bundle, jspm will stumble over the '@empty/lib/jsdom/living/generated/utils'
require statement.
Error: ENOENT: no such file or directory, open '/Users/dkoerner/projects/JSPMFabricTestCase/@empty/lib/jsdom/living/generated/utils.js'
jspm treated the jsdom
entries first as required by the package.json
, thereby failing to recognize the more detailled entry 'jsdom/lib/jsdom/living/generated/utils'
. It is necessary to provide the map in the correct order - long paths before short paths.
This can be achieved with a local override as depicted in the solution above. Please note that jsdom
is ordered below @empty/lib/jsdom/living/generated/utils
in the override, as opposed to the original package.json
.