Skip to content

Dynamic require only works after hot reload / incremental build  #6629

@pierrebeaucamp

Description

@pierrebeaucamp

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Related issues might be #5275 and / or #4431

Versions.

@angular/cli: 1.0.0 (e)
node: 7.8.0
os: linux x64
@angular/common: 4.1.3
@angular/compiler: 4.1.3
@angular/core: 4.1.3
@angular/forms: 4.1.3
@angular/http: 4.1.3
@angular/platform-browser: 4.1.3
@angular/platform-browser-dynamic: 4.1.3
@angular/router: 4.1.3
@angular/cli: 1.0.0
@angular/compiler-cli: 4.1.3

Also reproducible using @ngtools/webpack version 1.4.1, 1.4.0, 1.2.7. I did not check any version before 1.2.7.

Further, the bug was also reproduced on OSX.

Repro steps.

After running ng new, I modified the following files like this:

src/app/app.component.html
<h1>
  {{title}}
</h1>

{{foobar}}
src/app/app.component.ts
import { Component } from '@angular/core';

declare function require(string):string;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
  foobar:string;

  constructor() {
    let filename = 'foobar';
    this.foobar = require('./' + filename + '.html');
  }
}
src/app/foobar.html
This should be dynamically required

Then, ng serve. I also tested this with ng eject and npm start (same behavior).

The log given by the failure.

ERROR Error: Cannot find module "."
Stack trace:
webpackMissingModule@http://localhost:4200/main.bundle.js:58:67
AppComponent@http://localhost:4200/main.bundle.js:58:34
createClass@http://localhost:4200/vendor.bundle.js:11809:26
createDirectiveInstance@http://localhost:4200/vendor.bundle.js:11643:37
createViewNodes@http://localhost:4200/vendor.bundle.js:13006:49
createRootView@http://localhost:4200/vendor.bundle.js:12911:5
callWithDebugContext@http://localhost:4200/vendor.bundle.js:14126:39
debugCreateRootView@http://localhost:4200/vendor.bundle.js:13586:12
ComponentFactory_.prototype.create@http://localhost:4200/vendor.bundle.js:10832:37
ComponentFactoryBoundToModule.prototype.create@http://localhost:4200/vendor.bundle.js:4368:16
ApplicationRef_.prototype.bootstrap@http://localhost:4200/vendor.bundle.js:5952:40
PlatformRef_.prototype._moduleDoBootstrap/<@http://localhost:4200/vendor.bundle.js:5741:72
PlatformRef_.prototype._moduleDoBootstrap@http://localhost:4200/vendor.bundle.js:5741:13
PlatformRef_.prototype._bootstrapModuleFactoryWithZone/</</<@http://localhost:4200/vendor.bundle.js:5703:21
ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.bundle.js:2835:17
onInvoke@http://localhost:4200/vendor.bundle.js:5069:28
ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.bundle.js:2834:17
Zone.prototype.run@http://localhost:4200/polyfills.bundle.js:2585:24
scheduleResolveOrReject/<@http://localhost:4200/polyfills.bundle.js:3262:52
ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.bundle.js:2868:17
onInvokeTask@http://localhost:4200/vendor.bundle.js:5060:28
ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.bundle.js:2867:17
Zone.prototype.runTask@http://localhost:4200/polyfills.bundle.js:2635:28
drainMicroTaskQueue@http://localhost:4200/polyfills.bundle.js:3028:25

ERROR CONTEXT Object { view: Object, nodeIndex: 1, nodeDef: Object, elDef: Object, elView: Object }

Desired functionality.

localhost:4200 should show:

app works!
This should be dynamically required 

Mention any other details that might be useful.

The really weird thing about this bug is that it only occurs on the first build of the file. While ng serve or npm start is running, I can open src/app/app.component/ts and save it (without any changes). The app compiles and works just fine.


Edit:

I tried using System.import instead of require, but the same problem still exists. Doesn't work on first build, works after saving the file while ng is watching.

Edit 2:

Explicitly disabling aot doesn't help either (using ng serve --no-aot, ng serve --aot false, or ng serve --aot=false

Edit 3:

I experimented a bit more with System.import. My component looks like this:

import { Component } from '@angular/core';

declare var System:any;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
  foobar:string;

  constructor() {
    let filename = 'foobar';
    System.import('./' + filename + '.html').then((file) => {
      this.foobar = file;
    });
  }
}

On first compilation, the output is:

** NG Live Development Server is running on http://localhost:4200 **
Hash: 9b75b2c6426cd3555cd8
Time: 12211ms
chunk    {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 160 kB {4} [initial] [rendered]
chunk    {1} main.bundle.js, main.bundle.js.map (main) 4.32 kB {3} [initial] [rendered]
chunk    {2} styles.bundle.js, styles.bundle.js.map (styles) 9.77 kB {4} [initial] [rendered]
chunk    {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.4 MB [initial] [rendered]
chunk    {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]
webpack: Compiled successfully.

Then, if I open the file and save it, the output of webpack is:

webpack: Compiling...
Hash: d72262bdb116e279e8db
Time: 455ms
chunk    {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 160 kB {4} [initial]
chunk    {1} main.bundle.js, main.bundle.js.map (main) 4.32 kB {3} [initial] [rendered]
chunk    {2} styles.bundle.js, styles.bundle.js.map (styles) 9.77 kB {4} [initial]
chunk    {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.4 MB [initial]
chunk    {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry]
chunk    {5} 5.chunk.js, 5.chunk.js.map 58 bytes {1} [rendered]
webpack: Compiled successfully.

As you can see, the incremental build includes a chunk file (and everything works as expected).

Edit 4:

ng build and serving it using a standalone server doesn't solve the problem.

Edit 5:

Since System.import is deprecated in webpack, I tried using require.ensure, however I get the exact behavior as previously with System.import

Edit 6:

I tried using typescript 2.4.0, since it supports native import statements. I had to change the module compiler option in src/tsconfig.app.json for it to compile, but didn't have much luck - it appears to be broken in a different way than this bug and I couldn't get it to work at all.

Edit 7:

Same behavior using require.context.

Metadata

Metadata

Assignees

Labels

P5The team acknowledges the request but does not plan to address it, it remains open for discussionseverity1: confusing

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions