How can I make Cesium, SystemJS, and Angular2 compatible with each other?

Could anyone provide a working example of using SystemJS (not Webpack) with Angular2 (in TypeScript, not Dart) and Cesium (npm)?

I came across a blog post on cesiumjs' site that discusses this:

The author mentioned, "You can't simply do a require('cesium')." However, the article focuses on the Webpack way which I don't have access to.

I am encountering this error in the browser:

Error: (SystemJS) AMD module http://localhost:3000/node_modules/cesium/Build/CesiumUnminified/Cesium.js did not define

This is what my systemjs.config.js file looks like:

paths: {'npm:' :  'node_modules/'},
map: {
    app: 'dist',
    '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
    ...
    'require': 'npm:requirejs/require.js',
    'cesium': 'npm:cesium/Build/CesiumUnminified/Cesium.js',
    ...
}

Example of using @Injectable():

let Cesium = require('cesium');
import { Injectable } from '@angular/core';

@Injectable()

export class CesiumClock {
    private _start:any = Cesium.JulianDate.now();
    private _stop:any = Cesium.JulianDate.addHours(this._start,12,new Cesium.JulianDate());
    private _clock:any = new Cesium.Clock({
        startTime: this._start,
        stopTime: this._stop,
        currentTime: this._start,
        clockRange: Cesium.ClockRange.LOOP_STOP,
        mutliplier: 1,
        shouldAnimate: true
    });
}

And here's the client code that attempts to use my 'CesiumClock', resulting in an error in the browser after transpiling:

import { Component } from '@angular/core';
import { CesiumClock } from '../services/index';

@Component({
    moduleId: module.id.replace("/dist", "/app"),
    templateUrl: 'stuff.component.html',
    styleUrls: [
        'stuff.css',
        'node_modules/cesium/Build/Cesium/Widgets/widgets.css'
    ]
 })

export class StuffComponent {
    constructor(private _cesiumClock:CesiumClock) {}
}

UPDATE:

Thanks to @artem's input, I managed to resolve the specific 'Error: (SystemJS) AMD' issue in the browser. However, now when trying to utilize anything related to Cesium, such as new Cesium.Viewer(...), the Cesium object appears empty leading to the error

Cesium.Viewer is not a constructor

Answer №1

Big shoutout to @artem for shedding light on this issue. Here's the final solution that really worked for me:

systemjs.config.js (Check out 'cesium' under packages and take note of the global variable, CESIUM_BASE_URL)

(function(global){
    global.CESIUM_BASE_URL = './node_modules/cesium/Build/CesiumUnminified';
    System.config({
        paths: {
            // aliases for paths
            'npm:': 'node_modules/'
        },
        map: {
            ...
            // aliases for paths
            'cesium': 'npm:cesium/Build/CesiumUnminified'
            ...
        },
        packages: {
            ...
            'cesium': {
                main: './Cesium.js',
                meta: {
                    '*.js': {
                        format: 'cjs'
                    }
                }
            },
            ...
        }
    });
})(this);

cesium.viewer.ts (Note how declare and import are combined. The declare statement lets the TypeScript compiler recognize Cesium, while the import ensures it works in the browser.)

declare var Cesium:any;
import 'cesium';

@Injectable()
export class CesiumViewer {
    ...
    this._viewer = new Cesium.Viewer(elem, {...});
    ...
}

I think the meta section is crucial because Cesium requires multiple .js files. Without the meta *.js property, only Cesium.js is fetched, which isn't sufficient, whether minified or not, sourced or not.

Now that the JavaScript part is sorted, I'm facing a major CSS crisis - the Cesium map looks like a complete mess in the browser.

Answer №2

SystemJS automatically detects the format for CesiumUnminified/Cesium.js as amd, but strangely it does not function properly as an amd module with SystemJS. However, it can be successfully loaded if you adjust its format to CommonJS:

    map: {
         ...
        'cesium': 'npm:cesium/Build/CesiumUnminified',

and

    packages: {
            ...
        cesium: {
            main: 'Cesium.js',
            format: 'cjs'
        },

Update: It seems that SystemJS struggles to utilize both versions provided in node_modules/cesium/Build: specifying either mapping to Cesium or CesiumUnminified in Build results in

import Cesium = require('cesium');
returning an empty object.

However, the Cesium file can be properly loaded from the sources provided in node_modules/cesium/Source. By removing format: 'cjs' from the cesium package and changing the mapping to 'cesium': 'npm:cesium/Source', I was able to execute this code:

 import Cesium = require('cesium');
 console.dir(Cesium.Viewer);

which resulted in:

 function Viewer(container, options)

being printed out in the console. The actual functionality of this is uncertain at this point.

Answer №3

I successfully integrated Cesium with Angular 2 and SystemJS after making some tweaks to the config file, as the solutions shared previously didn't quite work in my case.

Here is the updated systemjs.config.js file:

(function (global) {
  global.CESIUM_BASE_URL = './node_modules/cesium/Build/CesiumUnminified';
  System.config({
    paths: {
      // paths serve as alias
      'npm:': 'node_modules/'
    },
    // map tells the System loader where to look for things
    map: {
     ...
     'cesium': 'npm:cesium/Build/CesiumUnminified'
     ...
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
  ...
  'cesium': {
    main: './Cesium.js',
    meta: {
      '*.js': {
        format: 'global'
      }
    }
  }
}
});
})(this);

Additionally, I added this line to app.component.js:

import 'cesium';

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it necessary to only override the monospaced font?

Can the monospace font in Angular Material be customized for just the <code>foo</code> blocks? I want to use a font where the number zero 0 looks distinct from the letter oh O. ...

Make Ionic 2 Navbar exclusively utilize setRoot() instead of pop()

When navigating to a different page, the ion-navbar component automatically includes a back button that uses the pop() method to return to the previous page. Is there a way to modify this behavior so that it utilizes the setRoot() method instead of pop(), ...

What is the process for connecting a global variable to a BehaviorSubject?

I'm currently working on implementing a login feature in my application, and I want specific buttons within the app.component template to only be visible once the user successfully logs in. To achieve this, I am attempting to utilize BehaviorSubject. ...

Adding an interface for an object containing multiple objects requires defining the structure and behavior

I'm in the process of designing an interface for my object. Here is the data structure of the object: { "isLoaded": true, "items": { "0": { "name": "Mark", "age": "40" }, "1": { "name": " ...

Exploring Angular 2 Application Testing: Tips for Interacting with HTML Elements

In my Angular 2 Frontend testing journey, I came across a blog post ( ) where the author utilized ng-test TestBed for core testing in Angular. While the example provided was helpful for basic understanding, it lacked details on how to manipulate Elements. ...

What is the process for executing a particular NPM command prior to building in ASP.NET Core?

I need to execute a specific NPM command for Angular within my ASP.NET Core application. The command is simple, it just prepares some files. Is there a way to automate running the NPM script before each build in ASP.NET Core? The Angular app is located i ...

Can conditional content projection (transclusion) be achieved in Angular 2+?

How can I set default content that will only display if content is not transcluded? Consider the following component template: <article> <header> <ng-content select="[header]"></ng-content> </header> < ...

Unable to test the subscribe functionality in Angular

There is a subscribe method in my ts file within ngAfterViewInit() that is not triggering as expected during testing and debugging. I need to manually set mock data inside the subscribe method for testing purposes. ts file import mockData from 'test ...

Aurelia validation is failing to work properly when the form is already populated with data

Struggling to implement validation on an edit model-view that is data-bound in the activate method of its view-model. The create.ts file works smoothly with similar code, but without the need to load data. Surprisingly, the validation functions correctly ...

Having trouble with installing angular-cli

angular-cli unexpectedly quits while trying installing: (myapp)vagrant@myapp-local:/vagrant$ sudo npm install -g angular-cli npm WARN deprecated <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="caadb8aba9afacbfa6e7acb98afbe4f8e4 ...

Tips for triggering an error using promise.all in the absence of any returned data?

I'm dealing with an issue in my project where I need to handle errors if the API response returns no data. How can I accomplish this using Promise.all? export const fruitsColor = async () : Promise => { const response = await fetch(`....`); if( ...

Angular 4 lazy loading feature is malfunctioning

I've been working on implementing lazy loading in my angular4 project, following all the steps outlined in the documentation without success. Here is a snippet of my code: StudentModule: import { NgModule } from '@angular/core'; import { ...

Encountering RxJS errors during the process of constructing an object using streams retrieved from Firebase

I am currently in the process of developing a template-driven form that involves multiple streams from Firebase. Despite my efforts, I keep encountering errors with the json pipe. The error message I receive is "Converting circular structure to JSON as ...

Guide on retrieving the interface property name or key name as a string in Typescript

Currently, I am utilizing the API of Slack and encountering situations where I send JSON requests containing strings that return as property names later on. I want to create an interface where I can send one of its property names as a string and receive t ...

Removing a value from a hashmap using Typescript - what is the best way to do it?

After successfully implementing a hashmap in typescript following a helpful post, I am facing an issue with removing something from the hashmap. TypeScript hashmap/dictionary interface To add a key to the keys field of my abstract Input class's hash ...

What is the role of the "prepare" function in AWS CDK constructs?

TL;DR: What is the role and purpose of the prepare(): void method in AWS CDK's Construct class? When and how should it be utilized or avoided? The information provided about prepare() states: prepare() function is called after child constructs have ...

Developing a calendar UI with similar features and functionality to Google Calendar using Ionic 2

My journey with Ionic 2 began only one week ago and has been relatively smooth sailing thus far. However, I have hit a roadblock - I need to create a calendar interface for users to book time slots. Can anyone offer assistance on how to tackle this task? ...

Is it possible to utilize an npm package in TypeScript without a d.ts definition file?

Is it possible to use an npm package in TypeScript and Node.js without a .d.ts definition file? If so, how can I make it work? Currently, my code looks like this and I'm getting an error that says "cannot find module 'node-rest-client'" bec ...

Angular 7: Separate Views for Search Bar and Results

Two components have been developed: search-bar.component.ts: displayed in all views search.component.ts: responsible for displaying the results (response from a REST API) The functionality is as follows: whenever I need to perform a global search (produ ...

Loading the value of a Subject variable in an Angular 2 application using Typescript

I am currently developing an Angular2 application where I am loading data from a service into my component as a subject. public type1Choisi: any; constructor( public formeService: FormeService, ...) { this.formeService._type1.subscribe(type1 => ...