Angular 10+ @bokeh/bokehjs not compiling (or with webpack)

Hello,

I am trying to work with bokehJS + Angular (specifically 10+, and at least bokeh 2.2.3) at the moment, and having some issues with running.

I have some examples working using CDN and some html files, works great. What I am trying to do is a simple test and have a component (my) be able to plot in Angular, such that,

<!--my.component.html-->
<div id="bokeh-chart"></div>
/* my.component.ts */
import { Component, OnInit } from '@angular/core';
import * as Bokeh from '@bokeh/bokehjs/'; 

@Component({
  selector: 'app-chart',
  templateUrl: './chart.component.html',
  styleUrls: ['./chart.component.scss']
})
export class ChartComponent implements OnInit {

  constructor() { 
    const plt = Bokeh.Plotting;

    let x = Bokeh.LinAlg.linspace({0, 10, 20});
    let y = x.map(function(v) {return v**2;});

    let source = Bokeh.ColumnDataSource({
      data: {x : x, y : y}
    });

    p = plt.figure({title : "My Plot"});
    line = p.line({field: x}, {field: y}, {source: source});

    plt.show(p, '#bokeh-chart');
  }

  ngOnInit(): void {
}

I have had a look at the posts here and saw similar posts related to the issue,

  1. Angular 10 + @bokeh/bokehjs
  2. Node12 import error bokeh 2.0
  3. Using BokehJS in an Angular app
  4. [BUG] @bokeh/[email protected] breaks babel compile · Issue #10959 · bokeh/bokeh · GitHub
  5. Add examples/bokehjs directory · Issue #10962 · bokeh/bokeh · GitHub

I see that [2] references @craco/craco but that is for react. Using this example, based on [4, 5] seems to generate the same error when you adjust the filenames to the correct output file.

From running Angular

If calling this in the my.component.ts

import * as Bokeh from '@bokeh/bokehjs';
...
let plt = Bokeh.Plotting;
ERROR in ./node_modules/@bokeh/bokehjs/build/js/lib/index.js 3:9
Module parse failed: Unexpected token (3:9)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| export { version } from "./version";
| export { index } from "./embed";
> export * as embed from "./embed";
| export * as protocol from "./protocol";
| export * as _testing from "./testing";

If you try to be more direct with the file paths in the Angular import it compiles fine, but the browser page is empty (sans some html) and the error is as follows

my.component.ts

import {LinAlg, Plotting} from '@bokeh/bokehjs/build/js/lib/api';
...
let plt = Plotting;

Browser error

Uncaught ReferenceError: can't access lexical declaration 'HasProps' before initialization
    node_modules vendor.js:52587
    node_modules vendor.js:63169
    Webpack 42
has_props.js:1
...

bokehjs-example error

This error was when running npm install and npm run build as seen in

ERROR in ./node_modules/bokehjs/build/js/lib/index.js 3:9
Module parse failed: Unexpected token (3:9)
You may need an appropriate loader to handle this file type.
| export { version } from "./version";
| export { index } from "./embed";
> export * as embed from "./embed";
| export * as protocol from "./protocol";
| export * as _testing from "./testing";
 @ ./node_modules/bokehjs/build/js/lib/main.js 1:0-24 1:0-24
 @ ./node_modules/bokehjs/build/js/lib/bokeh.js
 @ ./src/index.js

ERROR in bundle.js from Terser
Octal escape sequences are not allowed in template strings [bundle.js:42790,26]

Does anyone have any insight on what I may try?

Module parse failed: Unexpected token (3:9)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See Concepts | webpack

export { version } from "./version";
export { index } from "./embed";
export * as embed from "./embed";

It looks like your setup doesn’t support export * as X from "Y" syntax. You will either have to bump the minimal supported version of ECMAScript to (I think) ES2020 (if desired of course) (whatever that means in webpack) or transpile ES2020 to the version supported by your setup (perhaps configure a loader as the error message suggests).

1 Like

Octal escape sequences are not allowed in template strings [bundle.js:42790,26]

Hard to tell the reason without knowing how the code was transformed and otherwise mangled till this point. However, I’m guessing it’s just a side effect of mismatch between the version of ES that the imported bokeh code uses and what the your setup expects. As mentioned earlier, everything under bokehjs/build/js/lib is ES2020 (I’m assuming bokehjs 2.4).

1 Like

Hi @mateusz,

Thanks for reaching out. I technically am using bokehjs 2.2.3, (trying to stay compatible with work, but we can upgrade).

I believe based on the tsconfig.base.json file from the angular project, it is… 2015? or 2018?

/* To learn more about this file see: https://angular.io/config/tsconfig. */ 
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2015",
    "module": "es2020",
    "lib": [
      "es2018",
      "dom"
    ]
  }
}

I did upgrade at one point to bokehjs 2.4, and there was much more noise for errors. Is there anything I should be looking for or can provide to help with understanding this problem?

I decided to just install nodejs LTS (16.x.x), and bump up to using angular/[email protected] (in a clean project only with @bokeh/bokehjs installed) which by default sets all ECMAScript to ES2020, but now I get a new error.

When I just include the line in my component import * as Bokeh from '@bokeh/bokehjs';, and run npx ng serve I get errors relating to being able to find module “core/kinds” or the MathJax namespace. Which is now very different.

Any idea what is going on here? I appreciate any help or direction!

$  npx ng serve
✔ Browser application bundle generation complete.

Initial Chunk Files   | Names         |  Raw Size
vendor.js             | vendor        |   1.73 MB |
polyfills.js          | polyfills     | 315.29 kB |
styles.css, styles.js | styles        | 207.83 kB |
main.js               | main          |  49.35 kB |
runtime.js            | runtime       |   6.51 kB |

                      | Initial Total |   2.29 MB

Build at: 2022-08-22T14:24:12.037Z - Hash: 7d3b71a1cfb0497f - Time: 11883ms

Error: node_modules/@bokeh/bokehjs/build/js/types/models/ranges/factor_range.d.ts:10:37 - error TS2307: Cannot find module 'core/kinds' or its corresponding type declarations.

10 export declare const Factor: import("core/kinds").Kinds.Or<[string, [string, string], [string, string, string]]>;
                                       ~~~~~~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/ranges/factor_range.d.ts:11:40 - error TS2307: Cannot find module 'core/kinds' or its corresponding type declarations.

11 export declare const FactorSeq: import("core/kinds").Kinds.Or<[string[], [string, string][], [string, string, string][]]>;
                                          ~~~~~~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/text/mathjax/index.d.ts:1:60 - error TS2503: Cannot find namespace 'MathJax'.

1 export declare function tex2svg(formula: string, options?: MathJax.ConvertOptions, macros?: MathJax.TeXMacros): HTMLElement;
                                                             ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/text/mathjax/index.d.ts:1:93 - error TS2503: Cannot find namespace 'MathJax'.

1 export declare function tex2svg(formula: string, options?: MathJax.ConvertOptions, macros?: MathJax.TeXMacros): HTMLElement;
                                                                                              ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/text/mathjax/index.d.ts:4:49 - error TS2503: Cannot find namespace 'MathJax'.

4 export declare function find_tex(text: string): MathJax.ProtoItem[];
                                                  ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/text/providers.d.ts:6:36 - error TS2304: Cannot find name 'MathJax'.

6     abstract get MathJax(): typeof MathJax | null;
                                     ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/text/providers.d.ts:14:27 - error TS2304: Cannot find name 'MathJax'.

14     get MathJax(): typeof MathJax | null;
                             ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/text/providers.d.ts:18:22 - error TS2304: Cannot find name 'MathJax'.

18     _mathjax: typeof MathJax | null;
                        ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/text/providers.d.ts:19:27 - error TS2304: Cannot find name 'MathJax'.

19     get MathJax(): typeof MathJax | null;
                             ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/widgets/multichoice.d.ts:7:26 - error TS2709: Cannot use namespace 'Choices' as a type.

7     protected choice_el: Choices;
                           ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/widgets/tables/row_aggregators.d.ts:27:44 - error TS2344: Type 'unknown' does not satisfy the constraint 'SlickData'.

27     storeResult: (groupTotals: GroupTotals<unknown>) => void;
                                              ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/widgets/tables/row_aggregators.d.ts:33:44 - error TS2344: Type 'unknown' does not satisfy the constraint 'SlickData'.

33     storeResult: (groupTotals: GroupTotals<unknown>) => void;
                                              ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/widgets/tables/row_aggregators.d.ts:39:44 - error TS2344: Type 'unknown' does not satisfy the constraint 'SlickData'.

39     storeResult: (groupTotals: GroupTotals<unknown>) => void;
                                              ~~~~~~~


Error: node_modules/@bokeh/bokehjs/build/js/types/models/widgets/tables/row_aggregators.d.ts:45:44 - error TS2344: Type 'unknown' does not satisfy the constraint 'SlickData'.

45     storeResult: (groupTotals: GroupTotals<unknown>) => void;
                                              ~~~~~~~




** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **


✖ Failed to compile.

Config files

tsconfig.json,

{
  "compileOnSave": false,
  "compilerOptions": {
    "allowJs": true, /* Required for choices.js module */
    "checkJs": true, /* Required for choices.js module */
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2020",
    "module": "es2020",
    "lib": [
      "es2020",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

Due to not having proper checks I needed to load choices.js for compilation,

src/choices.js.d.ts

declare module 'choices.js';

Okay, so I seem to have a working version (with some warnings), that makes a very simple plot. Thanks @mateusz for pointing me in the right direction to start. I am just learning Angular so a lot of what is going on is new for me.

Installation

Assuming you have a compatible version of node and npm for Angular 14, and bokehjs 2.4.3, this works. If using Ubuntu/Debian.

Node.js LTS (v16.x)

This is taken from the official installer page,

# Using Ubuntu 
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - 
sudo apt-get install -y nodejs 

# Using Debian, as root 
curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - 
apt-get install -y nodejs

Then we can install Angular. Note I am installing Angular 14 in a local directory instead of globally, as I am just testing. You can change it if you so desire.

mkdir angular14
cd angular14
npm install @angular/[email protected]

Now we can create our project

Setting up the project

npx ng new bokehdemo

Aside: Just as a warning for having the tool icons show up in the toolbar Do not include the bokehjs files in src/index.html as outlined in the official documentation

<!-- angular14/bokehdemo/src/index.html -->
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Frontend</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <!-- DO NOT INCLUDE THE BOKEHJS SCRIPTS HERE -->
</head>
<body>
  <app-root></app-root>
</body>
</html>

Declaring modules

Much like the issue above with choices.js, we need to declare a module for choices.js and Bokeh API. To do that we can create two files in the angular14/bokeh-demo/src directory,

/* angular14/bokehdemo/src/choices.js.d.ts*/
declare module 'choices.js'
/* angular14/bokehdemo/src/bokehjs.d.ts 
 * You could get away with just the api for this example but, I put the rest
 * here incase
 */
declare module '@bokeh/bokehjs/build/js/lib/embed';
declare module '@bokeh/bokehjs/build/js/lib/client';
declare module '@bokeh/bokehjs/build/js/lib/document';
declare module '@bokeh/bokehjs/build/js/lib/core';
declare module '@bokeh/bokehjs/build/js/lib/api';
declare module '@bokeh/bokehjs/build/js/lib/protocol';
declare module '@bokeh/bokehjs/build/js/lib/models';

Creating out simple component

npx ng generate component/plot

We can add the basics of our plot by modifying the component html and ts files, first the typescript file,

/* angular14/bokehdemo/src/app/plot/plot.component.ts */
import { Component, OnInit } from '@angular/core';
import * as Bokeh from '@bokeh/bokehjs/build/js/lib/api';

@Component({
  selector: 'app-plot',
  templateUrl: './plot.component.html',
  styleUrls: ['./plot.component.scss']
})
export class PlotComponent implements OnInit {

  constructor() { 
    const plt = Bokeh.Plotting;
    const la = Bokeh.LinAlg;
    
    let x = la.linspace(0, 10, 20);
    let y = x.map(function(v: number) { return v**2 });

    let source = new Bokeh.ColumnDataSource({
      data: {x: x, y: y}
    });
    
    let tools = "pan,crosshair,wheel_zoom,box_zoom,reset,save";
    let p = plt.figure({title: "Test", tools: tools});
    
    let line = p.line(
      {field: 'x'},
      {field: 'y'},
      {source: source, linewidth: 2},
    );

    plt.show(p, '#bokeh-chart');
  }

  ngOnInit(): void {
  }

}

Now the html template

/* angular14/bokehdemo/src/app/plot/plot.component.html */
<div id="bokeh-chart"></div>

And finally the application component template,

/* angular14/bokehdemo/src/app/app.component.html */
<h1> {{ title }} </h1>
<app-plot></app-plot>

Run the server to test

You should be now able to test if bokehjs works!

npx ng serve

Yay! (or Yay?)

Caveats / Warnings

You may get some warnings about slowdowns due to using CommonJS or AMD dependencies, but I haven’t stress tested these.

$ npx ng serve
✔ Browser application bundle generation complete.

Initial Chunk Files                                                                                     | Names         |  Raw Size
vendor.js                                                                                               | vendor        |   3.87 MB |
polyfills.js                                                                                            | polyfills     | 315.33 kB |
styles.css, styles.js                                                                                   | styles        | 207.87 kB |
runtime.js                                                                                              | runtime       |  12.62 kB |
main.js                                                                                                 | main          |   8.65 kB |

| Initial Total |   4.40 MB

Lazy Chunk Files                                                                                        | Names         |  Raw Size
node_modules_bokeh_bokehjs_build_js_lib_models_text_mathjax_index_js.js                                 | mathjax       |   2.41 MB |
node_modules_bokeh_bokehjs_build_js_lib_models_glyphs_webgl_index_js.js                                 | glyphs-webgl  | 370.56 kB |
common.js                                                                                               | common        |  22.52 kB |
default-node_modules_bokeh_bokehjs_build_js_lib_models_glyphs_webgl_base_marker_js.js                   | glyphs-webgl  |  14.64 kB |
node_modules_bokeh_bokehjs_build_js_lib_models_glyphs_webgl_base_js-node_modules_bokeh_bokehj-4e4a28.js | webgl-line_gl |  10.05 kB |

Build at: 2022-08-23T22:12:25.258Z - Hash: c44c46c78398971f - Time: 4972ms

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/core/util/templating.js depends on '@bokeh/numbro'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/core/util/templating.js depends on 'sprintf-js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/core/util/templating.js depends on 'timezone'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/glyphs/webgl/regl_wrap.js depends on 'regl'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/adaptors/browserAdaptor'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/handlers/html.js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/input/mathml'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/input/tex.js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/input/tex/AllPackages.js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/input/tex/FindTeX.js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/mathjax.js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Warning: /home/user/angular14/bokehdemo/node_modules/@bokeh/bokehjs/build/js/lib/models/text/mathjax/index.js depends on 'mathjax-full/js/output/svg.js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies



** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **


✔ Compiled successfully.

Any idea if I should be worried about these? Or how to deal with them?

1 Like

Just testing this on Debian Bullsye, and unfortunately, I don’t have the tools icons in the toolbar for the figure showing up. Any ideas on what this could be? (I did use the above steps). The hover tooltip on the buttons does work.

Edit: I lied, this issue was still present on Ubuntu Jammy. I think I got too excited because I have some moving widgets.

So looking at the CSS I see that it is available, but cancelled out? Here I am highlighting the bk-tool-pan

image

Strangely enough the Image is in the debugger, and you can click it and shows up as a valid image in the browser :confused:

What is strange is a few lines up for bk-logo-small it isn’t crossed out, and shows up in the html page normally.


PS side note, it makes sense to change my bokehjs.d.ts to be,

declare module '@bokeh/bokehjs/build/js/lib/embed';
declare module '@bokeh/bokehjs/build/js/lib/client';
declare module '@bokeh/bokehjs/build/js/lib/document';
declare module '@bokeh/bokehjs/build/js/lib/core';
declare module '@bokeh/bokehjs/build/js/lib/api';
declare module '@bokeh/bokehjs/build/js/lib/protocol';
declare module '@bokeh/bokehjs/build/js/lib/models';

As this should be more useful for people importing the bokeh modules, I updated above accordingly.


PPS Lol, @mateusz & @Bryan I am so sorry for all my posts. I think I solved it. Seconds later after this post I decided to comment out the <script src=bokeh.*></script> from the index.html file as such,

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>F14bk</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <!--script src="bokeh.min.js"></script>
  <script src="bokeh-widgets.min.js"></script>
  <script src="bokeh-tables.min.js"></script>
  <script src="bokeh-api.min.js"></script-->
</head>
<body>
  <app-root></app-root>
</body>
</html>

I double checked by removing them from the angular.json script : [...] tag as well and EVERYTHING worked fine. I think I was looking at the Minimal Example where you need to include the <script> tags at the beginning of the file, and that is not necessary here for the use case I have :confused:

See below for working icons!

I am updating the post above again with the corrections and will mark this solved.

Again, sorry for the noise.

1 Like