简体   繁体   中英

Webpack Fabric external is resolving to undefined

I'm setting up a project (typescript, webpack) with a couple of js libraries, configured as externals in webpack. They should not be part of the bundle, instead provided by script tags within the html.

But when trying to use them in my class, they resolve to undefined.

Fabric configured as an external in webpack is resolving to undefined

An error occurs when trying to set up the fabric js library as an external within a (typescript + webpack ) project. Fabric should not be bundled in the output file since it will be the responsibility of the consumer to provide (eg. through a browser script tag).

Note: jQuery initially had an issue (as an external) but is now resolved, and works as expected. Fabric on the other hand does not.

fabric has been configured as an external so that it will not be included in the webpack bundle.

Here's how...

  1. Added as an external within the webpack.config.js
...
  externals: {
    jquery: 'jQuery',
    fabric: 'fabric',
  },
...
  1. Installed the declaration files for both libraries
npm install @types/jquery -D
npm install @types/fabric -D
  1. Added the libraries in public folder and index.html (since they must not be part of the app bundle)
  <script src="js/lib/jquery.min.js"></script>
  <script src="js/lib/fabric.min.js"></script>
  1. Created a class App.ts, imported and implemented instances of these two libraries. (see App.ts)
import { fabric } from "fabric";
import $ from 'jquery';

fabric resolves to undefined within the class App.ts with the error:

TypeError: Cannot read property 'Canvas' of undefined

Please don't recommend ProvidePlugin or installing Babel.

More about webpack "externals": https://webpack.js.org/configuration/externals/


Update #1

jQuery is now working as an external library. I was not referencing the actual jquery global "jQuery" in the externals setup. I had "JQuery" (with a capital J). That's now resolved and jquery is working. Thanks @Aluan

Fabric on the other hand seems to be a different issue altogether.

What you're looking for is called shimming . Webpack docs cover this extensively here: https://webpack.js.org/guides/shimming/

Edit to add example:

In your webpack.config.js plugins array:

    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery"
        })
    ]

EDIT: I pulled down your code and got it working. Here are the steps:

  1. ts-loader chokes on shims, so use babel's @babel/preset-typescript -- otherwise you'll need to find a way to tell the ts compiler to ignore them. This will get you started:
npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-typescript core-js@3
  1. In your root, create a file called .babelrc and add the following:
{
    "presets": [
        "@babel/preset-typescript",
      [
        "@babel/env",
        {
          "targets": {
            "edge": "17",
            "firefox": "60",
            "chrome": "67",
            "safari": "11.1"
          },
          "useBuiltIns": "usage",
          "corejs": "3"
        }
      ]
    ]
  }
  1. Add this to your webpack.config.js :
  plugins: [
    new ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      fabric: "fabric"
    })
  ]
  1. Also update ts-loader , changing it to babel-loader .

  2. Now in your code, you'll need to prefix your shimmed libraries with window :

    constructor(private readonly selector: string, canvasHeight: number, canvasWidth: number) {
      
      window.$(`#${selector}`).replaceWith(`<canvas id="${selector}" height=${canvasHeight} width=${canvasWidth}> </canvas>`);

      this.canvas = new window.fabric.Canvas(`${selector}`, { selection: false });

    }

It turns out that the issue with fabric is from fabric itself! The reason fabric is resolving to undefined (when being configured as an external on webpack) is related to the way that fabric exposes its library for consumption. It's an issue they need to fix.

I've added an issue on the official fabric github page

But there is a quick solution for us. Just import using CommonJS like this:

const fabric = require('fabric');

Now it works!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM