Reputation: 3545
I spent quire a while to do AOT with angular 4, and always got this error: Uncaught ReferenceError: require is not defined
I got this error because I am using jquery in my app, and in the application, I am having this code:
var jQuery = require('jquery');
jQuery("xxxx").val()
If I remove this, the whole AOT worked like a charm.
My tsconfig-aot.json:
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"lib": ["es5", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
"files": [
"src/app/app.module.ts",
"src/main.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}
}
And my rollup config:
import rollup from 'rollup'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
export default {
entry: 'src/main.js',
dest: 'public/build.js', // output a single application bundle
sourceMap: false,
format: 'iife',
onwarn: function(warning) {
// Skip certain warnings
// should intercept ... but doesn't in some rollup versions
if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
// intercepts in some rollup versions
if ( warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; }
// console.warn everything else
console.warn( warning.message );
},
plugins: [
nodeResolve({jsnext: true, module: true}),
commonjs({
include: [ 'node_modules/rxjs/**','node_modules/jquery/**']
}),
uglify()
]
}
Does this mean, if you are using require() inside your ng4 app, then AOT will not work?
Thanks and hope to hear your advice.
I tried to use this: import * as jQuery from 'jquery'; Then it worked same as require, and in JIT mode, it worked fine. And also, ngc package is fine. But when I use roll-up, the out put has this error:
🚨 Cannot call a namespace ('jQuery')
src/app/app.component.js (14:8)
12: }
13: AppComponent.prototype.ngOnInit = function () {
14: jQuery('h1').html('New Content');
^
15: };
16: return AppComponent;
This is updated code:
import * as jQuery from 'jquery';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./scss/app.component.scss']
})
export class AppComponent implements OnInit{
ngOnInit(){
jQuery('h1').html('New Content');
}
}
Any idea?
Upvotes: 1
Views: 4527
Reputation: 31873
You can't use require
with --module es2015
.
It will cause a TypeScript compile error. The only reason it doesn't is that you are using the var..require
form instead of the correct, in TypeScript, import..require
form.
The only reason this doesn't raise a compile error is that there is an ambient declaration of require
somewhere such as in an @types package.
Still it is very unlikely to work because require is not part of the ignition module syntax and since you're using Rollup it's definitely not going to be recognized, at least not adding a bunch of plugins and configuration.
Try
import jQuery from 'jquery';
If the above throws at run time that jQuery is not defined, try
import * as jQuery from 'jquery';
Looking at your updated question I see you are receiving the error
Cannot call a namespace ('jQuery') Which is actually the correct spec compliant behavior when using the form
import * as ns from 'module';
to import from a CommonJS module that assigns to module.exports
(export = in TypeScript) in order to export its value.
Interop with CommonJS modules is supposed to make the value of module.exports
available under the default
export which will translate into the default
property of the module namespace object that is imported. That is to say the form
import jQuery from 'jquery';
is actually just a shorthand for
import {default as jQuery} from 'jquery';
Unfortunately, interop is far from smooth with many environments, transpilers, loaders, and bundlers handling it differently.
NodeJS itself does not even implement it.
This is one extremely rare area where TypeScript does the categorically wrong thing. It doesn't handle this case at all. Instead recommending the
import * as ns from 'module';
form which will fail in a spec compliant environment for
ns()
because the imported module namespace object has no [[Call]] slot.
Fortunately, you can sidestep this behavior, as you are currently doing, by having TypeScript output es2015
modules and processing them with another tool, such as Rollup.
Another option is to use TypeScript's system
module option and SystemJS.
This may seem a bit overly detailed and at the same time a bit hand waving, but I think it is important to realize how broken interop actually is so that we can fix it someday (I hope).
Update:
The TypeScript team is actively looking into the issue and it appears that the correct syntax
import jQuery from 'jquery';
will eventually be supported by TypeScript without the need for another transpilation layer.
One day, your children will be able write web applications without having to know about this pitfall!
Upvotes: 2