Struggling to grasp the concept of how webpack consolidates dependencies into bundles

I'm having trouble grasping the concept of how webpack bundles dependencies together.

After creating a basic demo using webpack, typescript, and threejs, everything seems to be functioning properly. You can find the demo on GitHub here.

My first issue arises from not understanding how threejs is included in the bundle.js. Although it works well, I am perplexed about its inclusion.

The next hurdle appeared when attempting to introduce another package (npm install --save three.trackball). I also added the necessary typings for it with:

typings install --save --global dt~three-trackballcontrols

Although the compilation goes smoothly, loading the content in the browser results in the error:

THREE.TrackballControls is not a constructor

I understand why this occurs: the trackball JS file is missing in the HTML. However, I am struggling to figure out how to include it, particularly since I cannot comprehend how the three dependency is being brought in!

You can find the work-in-progress trackball feature in the mentioned repository under the branch WIP-trackball.

Answer №1

When setting up an angular2/typescript project using angular-cli, I encountered a challenge with webpack configuration not being exposed by angular-cli which now uses webpack internally.

A similar issue arose when working with Three.js TrackballControls. Eventually, I managed to resolve it by adding the necessary package to my package.json file.

"dependencies": {
  "@angular/common": "^2.4.0",
  "@angular/compiler": "^2.4.0",
  "@angular/core": "^2.4.0",
  "@angular/forms": "^2.4.0",
  "@angular/http": "^2.4.0",
  "@angular/platform-browser": "^2.4.0",
  "@angular/platform-browser-dynamic": "^2.4.0",
  "@angular/router": "^3.4.0",
  "@types/three": "^0.83.3",
  "core-js": "^2.4.1",
  "rxjs": "^5.0.1",
  "three": "^0.84.0",
  "three-trackballcontrols": "^0.0.5",
  "ts-helpers": "^1.1.1",
  "zone.js": "^0.7.2"
},

Included in the @types for three, are the TrackballControls typings, however, the javascript is not part of the three module.

The current challenge I'm facing is the inability to use the import statement for three-trackballcontrols in my typescript files.

import TrackballControls from 'three-trackballcontrols'

This results in a "Cannot find module 'three-trackballcontrols'" error.

To work around this issue, I had to do the following:

//import TrackballControls from 'three-trackballcontrols'
var TrackballControls = require('three-trackballcontrols');

and

this.controls = new TrackballControls(this.camera, this.container);

within my typescript class.

I agree with Andrew E's explanation that there seems to be a confusion between two different trackball implementations for ThreeJS.

three.trackball: "Adaptation of three.js trackball control to commonjs module" offers a distinct implementation compared to three-trackballcontrols: "A module for using THREE.TrackballControls with nodejs". It appears that three-trackballcontrols aligns closely with the typings in the three module derived from the ThreeJS repository. While the interfaces may currently match, explicit typings might not be readily available for three.trackball.

Answer №2

Dealing with a similar issue, I encountered an error while attempting to include the TrackBallControls typescript file in my project:

THREE.TrackballControls is not a constructor

I realized that my three.d.ts file did not have a declaration for THREE.TrackballControls, so I appended my TrackBallControls at the end of the file with the "export" keyword, like this:

export class TrackballControls extends EventDispatcher {
    constructor(object: Camera, domElement?: HTMLElement);

    object: Camera;
    domElement: HTMLElement;

    // API (omitted for brevity)
    
}

I also included a new javascript file in my project with THREE.TrackballControls, which I found here.

Subsequently, I faced a TypeError related to my update function.

this.controls.addEventListener('change', this.render); 

Ultimately, I resolved it by commenting out the above line and retaining the following:

this.controls.update();

Since then, everything is functioning smoothly.

Answer №3

Provided below is a solution that serves as a partial answer and workaround instead of an "official" response. It is hoped that this will be beneficial to others.

To summarize:

In the webpack.config.js file, define THREE as an external module:

externals: {
  three: 'THREE'
},

This prevents THREE from being included in the bundle.js, which has its advantages and disadvantages. Overall, it is a positive outcome.

Concluding HTML script tags:

...
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="bundle.js"></script>
</body>
</html>

It should be noted that "external" does not imply "must originate from a third-party site". Rather, it signifies "not included in bundle.js".

More Detailed Explanation

I had been attempting to address numerous issues simultaneously. I had come to a realization similar to this:

"WebPack can gather all dependencies, such as THREE and trackball modules along with other THREE utility modules, incorporate them with typings information, package, compress, and bundle them into a single bundle.js file - so might as well do everything."

While this statement holds true, it is not the most efficient method to proceed.

Instead, I adopted the viewpoint that WebPack can neatly package the application code, and while it can package the vendor code too, doing so leads to various peculiar issues for limited benefit - thus, keeping those dependencies external is preferred.

In my attempts to include both THREE and trackball controls within the bundle.js, I encountered significant challenges. Integrating THREE itself was relatively straightforward and successful on the initial attempt, but incorporating the trackball or orbit controls presented perplexing obstacles.

There were multiple hurdles to overcome.

One issue stemmed from inaccurately named typing information for dt:

$ ls -C1 typings/globals/
three
three-orbitcontrols
three-trackballcontrols

These names are intuitive and sensible - however, the NPM modules differ:

$ grep -i three package.json
"three": "^0.77.1",
"three-orbit-controls": "^72.0.0",
"three.trackball": "0.0.1"

While uncertain, it appears that these naming disparities cause webpack difficulties in identifying which modules to include in the bundle based on imports.

Even after successfully importing, resolving the name THREE.OrbitControls proved elusive. The NPM module for the OrbitControls exports a function for invocation, requiring the existing THREE module as an argument before incorporating the OrbitControls. Despite this, the webpack initialization code lacks knowledge on how to execute this function, leaving me at a loss for resolution.

The following code snippet would result in compilation errors yet generate functional JS code:

import OrbitControls = require('three-orbitcontrols');
THREE.OrbitControls = OrbitControls(THREE);  // compile error but still emits JS that works

This approach demanded excessive effort for a simple concept: renaming directories, tweaking startup code, overlooking compile-time errors...

It gradually became apparent that there is no pressing need for THREE to be contained within the bundle, nor does it matter if the OrbitControls possess types or not. In fact, having a smaller bundle equates to improved speed and efficiency.

How can THREE be removed from the bundle? Simply declare it as external. Subsequently, the default NPM and typings modules operate seamlessly. Furthermore, the necessity of typings modules for the orbit or trackball controls remains uncertain.

Answer №4

Having tried the steps mentioned above without success, which included:

"three": "^0.84.0",
"@types/three": "^0.83.0",
"three-js": ">=79.0.0",
"three-trackballcontrols": "0.0.5",
"webpack": "^1.14.0"

I proceeded to take the following actions:

npm install save-dev three-trackballcontrols
mkdir node_modules/@types/three-trackballcontrols
cd node_modules/@types/three-trackballcontrols
cp ../three/three-trackballcontrols.d.ts ./index.d.ts

Subsequently, within index.d.ts, I modified

class TrackballControls extends EventDispatcher {...}
to
export class TrackballControls extends EventDispatcher {...}
.

Afterward, at the end of index.d.ts, I appended

declare module "three-trackballcontrols" {
  export = THREE.TrackballControls;
}

Then, moving on to the three typings section, I navigated to cd ../three and in index.d.ts, I changed

/// <reference path="three-trackballcontrols.d.ts" />
into a commented line
/* <reference path="three-trackballcontrols.d.ts" /> */

Lastly, in the renderer code, I utilized

import TrackballControls = require('three-trackballcontrols');
and initiated
controls = new TrackballControls(camera);
instead of
controls = new THREE.TrackballControls(camera);

Answer №5

I encountered a frustrating issue:

ERROR TypeError: WEBPACK_IMPORTED_MODULE_1_three.TrackballControls is not functioning as a constructor

This error surfaced after upgrading my project to angular-cli version 4.0. Sharing my code in hopes of aiding others.

Here's an excerpt from my package.json file:

"dependencies": {
    ...
    "three": "^0.82.1",
    "three-trackballcontrols": "0.0.5",
    ...
  },
"devDependencies": {
    ...
    "@types/three": "0.81.0",
    ...
  }

Within my Component.ts file:

...
import * as THREE from 'three';
import TrackballControls from "three-trackballcontrols";
...
this.webGLRenderer = new THREE.WebGLRenderer({antialias: true});
this.camera        = new THREE.PerspectiveCamera(
            this.view_angle,
            this.width / this.height,
            this.near,
            this.far
        );
...
this.controls = new TrackballControls(this.camera, this.webGLRenderer.domElement);

Answer №6

When working with Angular CLI (Angular 4), I encountered the same issue:

ERROR TypeError: __WEBPACK_IMPORTED_MODULE_1_three_trackballcontrols__.TrackballControls is not a constructor

Following mok's advice, I was able to resolve the error and get the code functioning properly.

One observation I made was that importing TrackballControls using the following syntax resulted in an error:

import { TrackballControls } from 'three-trackballcontrols';

A successful import should follow the method outlined by mok:

import TrackballControls from 'three-trackballcontrols';

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

Save geometric shapes data in the SQLite database

How do I go about storing polygon data in an SQLite database? Important: I am utilizing the Cordova plugin. polygon: Point[]; interface Point { x: number; y: number; } https://i.sstatic.net/5EYf2.png ...

What is the best method for generating type declarations efficiently?

What is the most effective method for generating type declarations in a Typescript project (library) while also transpiling and bundling code efficiently? I am currently utilizing webpack, ts-loader, and fork-ts-checker-webpack-plugin. During a single bu ...

Enforcement of static methods in Typescript abstract classes is not mandatory

In my TypeScript code, I have a simple structure defined: abstract class Config { readonly NAME: string; readonly TITLE: string; static CoreInterface: () => any } class Test implements Config { readonly NAME: string; readonly TITL ...

Ways to describe an item using a mix of determined and undetermined attributes

I am attempting to create a TypeScript type that includes properties I know and properties I do not know. Here is what I have tried: type MetaType = { res?: HttpResponse; req?: HttpRequest; [key: string]: string | number | boolean | string[] } ...

Choosing the Right Language for AngularJS 2: TypeScript, JavaScript, or Dart?

AngularJS 2 is on the horizon, and the documentation recommends three languages: Typescript, Javascript, and Dart. As someone who primarily works with Javascript EcmaScript 5, I'm curious about the strengths and weaknesses of these three options. Cu ...

What is the best way to assign a fixed name to files created within a bundle?

Currently, I am in the process of working on an MPA application using Vue CLI. When I create the bundle, Webpack automatically generates files as shown below: chunk-vendors.7f809fbd.js chunk-common.aae8cb13.js home.f85a21ab.js chunk-common.9113b70b.css etc ...

Mapping an array of keys to an array of properties using Typescript

Is there a way to achieve the following: type A = { a: string; b: number; c: boolean }; type B = ["b", "a"]; type C = MapProps<A, B> ?? // [number, string] The solution I have currently is: type C = {[key in B[number]]: A[key]} ...

Using Angular: Inject a different function after unsubscribing from the Timer Observable

I'm currently developing an exam app and I'm facing an issue where the view controller is getting stuck in a loop after unsubscribing from the timer. The goal is to notify the user when their time is up and redirect them to a results page. If an ...

Challenges arise when attempting to modify an ArrowHelper without creating a new instance

In my project using three.js, I am facing a challenge with updating the components of 3 ArrowHelper. Currently, I am able to update these 3 ArrowHelper in my animation by creating new instances each time the drawing function is called. For instance, in my ...

Angular: The Ultimate Guide to Reloading a Specific Section of HTML (Form/Div/Table)

On my create operation page, I have a form with two fields. When I reload the page using window.reload in code, I can see updates in the form. However, I want to trigger a refresh on the form by clicking a button. I need help writing a function that can r ...

What steps can be taken to troubleshoot the "error is not assignable to parameter of type" issue in

Do you have any suggestions on how to specify to TypeScript that I am passing the same required argument? Currently, I am encountering an error stating (is not assignable to parameter of type '{ [key: string]: ""; } ). If you could provide g ...

The element 'mdb-range-input' is not recognized. To ensure that it is a valid Angular component, please confirm that it is included in this module

Trying to implement a md bootstrap slider using the following code: <mdb-range-input (rangeValueChange)="onRangeValueChange($event)" id="range" min="0" max="100"></mdb-range-input> The module imports section includes: MDBBootstrapModule.forR ...

Ways to resolve issues related to null type checking in TypeScript

I am encountering an issue with a property that can be null in my code. Even though I check for the value not being null and being an array before adding a new value to it, the type checker still considers the value as potentially null. Can anyone shed lig ...

Creating a React component with a column allowing multiple checkbox selections in NextUI table

Setting up multiple "checkbox" columns in a table using the NextUI table has been my current challenge. Each row should have selectable checkboxes, and I want these selections to be remembered when navigating between pages, running searches, or removing co ...

Filtering data in TypeScript from a different component with the filter function

Currently, I am in the process of creating a filter function for a table. The table header and table body are separate components - with one responsible for filtering the data and the other for displaying it. User input is stored in the Table Header Compo ...

Learn the best way to retrieve the highest number from a Array<String> in TypeScript or JavaScript

Can someone help me create a function in JS or TS that meets the following requirements? I am looking for a functional programming approach. ・Input type: Array(String) ・Output type: string or undefined Examples Input Result ["" ...

A guide on implementing a return function in Typescript with Knockout

Seeking assistance with translating a JavaScript function to Typescript, which involves the use of knockout objects as entry parameters. Here are the TypeScript imports I am utilizing: import $ = require("jquery"); import ko = require("knockout"); Belo ...

Issues with the rating plugin functionality in Ionic 3

After following the instructions in this tutorial: http://ionicframework.com/docs/native/app-rate/ Even though I implemented the second method, I encountered the following error: Uncaught (in promise): TypeError: Cannot read property 'split' ...

Positioning of the child object in relation to the matrix of the

I'm working with three.js, and I have a container object (a cube that is 2.75 units long, 0.40 units wide, and 3.25 units high). I want to add 4 smaller objects (cubes that are 0.25 units long, 0.05 units wide, and 0.25 units high) to the corners of t ...

Using Angular2, assign a value to the session and retrieve a value from the session

I am having trouble getting and setting a session. Here is my code: login_btnClick() { var NTLoginID = ((document.getElementById("NTLoginID") as HTMLInputElement).value); this._homeService.get(Global.BASE_USER_ENDPOINT + '/EmployeeDe ...