Consume CommonJS Module Angular 2 - angularjs

I'm trying to write a simple Angular 2 application which consumes a CommonJS Node module (Node Yelp). Angular 2 by default uses SystemJS which has the ability to load different module formats.
I have tried several different SystemJS configurations and import statements, but all of them seem to end with
SyntaxError: Unexpected token <(…)
Currently, my SystemJS configuration looks like
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
},
map: {
yelp: 'node_modules/yelp'
}
});
System.import('app/main')
.then(null, console.error.bind(console));
and my simple AppComponent.ts
import {Component} from 'angular2/core';
import Yelp from 'yelp';
#Component({
selector: 'app',
templateUrl: '/app/app.component.html'
})
export class AppComponent {
constructor(yelp: Yelp) {
console.log(yelp);
}
}
I'm still trying to wrap my head around the whole module system, so I'm not exactly sure what to change here. Any results online seem to be out dated, or not direclty related to loading CommonJS node modules with SystemJS.

I think that you could try something like that:
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
},
yeld: {
main: index.js
}
},
map: {
yelp: 'node_modules/yelp'
}
});
and
import * as Yelp from 'yelp';

The solution, as I expected, turned out to be an easy one.
Don't try roll your own System.config when using NPM packages in Angular 2
Instead, use jspm to install packages. By doing so, all of the System.config will be taken care of by jspm. In this particular case, it was as easy as
jspm install npm:yelp
Then just adding
import Yelp from 'npm:yelp#1.0.1';
to the top of my AppComponent.ts file

Related

Requirejs callback undefined on code splitting

I'm a newbie to RequireJS I have a ReactJS app with index.jsx as an entry point
// index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
export function callBackForRequirejs() {
return "testing";
}
When I load my build via RequireJS I get these callbacks
require(["/path/to/bundle"], function(callback) {
console.log(callback) // I get "callBackForRequirejs"
}, function(err){
console.log(err)
});
But when I do code splitting I'm getting undefined in the callback, for code splitting I'm using these configs
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial",
}
}
}
}
UPDATE:
Actually, my react app is a plugin for some external app, the external app loads my plugin via RequireJS. The code inside an external app is something like this
case 1:
require(['/pathof/my/react/plugin/bundle.js'],
function(callbackwhenpluginloads){
callbackwhenpluginloads()
})
Since the size of my bundle.js is very large so I decided to split it into two parts one which comes from node_modules and one from my code
Now the external plugin loads my react plugin something like this
case 2:
require(['/pathof/my/react/plugin/bundle.js',
'/pathof/my/react/plugin/vendor.js' ], function(callbackwhenpluginloads){
callbackwhenpluginloads() // callbackwhenpluginloads is undefined
})
I'm getting undefined callback when the external app loads my plugin in
Actually, based on RequireJS docs for starting you did the following way and it works well:
require(['/path/to/bundle.js'], function(callback) {
console.log(callback) // you get callbackForRequireJS
}, function(error) {
console.log(error)
});
And now you did a code-splitting on your project, so you should consider this the vendor.js is like a dependency to split bundle.js file. so you should follow this example to load the dependencies at the first and then run the other split code. so your code is something like below:
requirejs.config({
paths: {
reactApp: 'path/to/bundle.js'
},
deps: ['path/to/vendor.js'],
});
require(['reactApp'], function(callback) {
console.log(callback) // it should works now
}, function(error) {
console.log(error)
});
Or there is another way that I don't recommend it:
require(['path/to/vendor.js'], function() {
require(['path/to/bundle.js'], function(callback) {
console.log(callback) // it should works now
}, function(bundleError) {
console.log('bundleError', bundleError)
});
}, function(vendorError) {
console.log('vendorError', vendorError)
});
It seems, for code splitting you are using the webpack. webpack and require js don't really get along.
you should try vanilla JS instead.
<script onload="handleOnLoad()" />
Or go for a npm package.
react-load-script - npm

Angular migration - Hybrid application is not bootstrapping

I am working on migrating my Angularjs 1.6 application to Angular 7 via ngUpgrade route, after all done when I'm trying to bootstrap my hybrid application, it's failing to bootstrap, I noticed that my main.ts file isn't executing at all where as I've added it as entry point in my webpack config.
I'm using template.ejs file as template in my HtmlWebpackPlugin. For Webpack settings and package.json, Please check my application bundling and bootstrapping code on github here:
https://github.com/mmmathur/AngularMigration
I tried with renaming it as index.ts as well but still no luck.
main.ts
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { UpgradeModule } from '#angular/upgrade/static';
import { AppModule } from '../client/ngApp/ngApp.module';
const app = require('../client/app');
let appRoot = document.createElement('div');
const uiView = document.createElement('ui-view');
let body = document.querySelector('body');
appRoot.appendChild(uiView);
body.appendChild(appRoot);
console.log('executing main.ts');//even this statement is not executed
platformBrowserDynamic().bootstrapModule(AppModule).then((platformRef) => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.documentElement, [app]);
console.log('hybrid application is bootstrapped');
})
.catch(err => console.error(err))
ngAppModule.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import {HttpModule} from '#angular/http';
import { FormsModule} from '#angular/forms';
import {UpgradeModule} from '#angular/upgrade/static';
import { AppComponent } from './ngApp.component';
#NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
UpgradeModule
],
declarations: [
AppComponent
],
bootstrap: [
AppComponent
],
entryComponents: [
]
})
export class AppModule {}
ngApp.component.ts
import { Component } from "#angular/core";
#Component({
selector: 'ng-app',
template: `
<div>
<h2>Angular 7 application bootstraped</h2>
</div>
`
})
export class AppComponent {}
Expected: my Hybrid application gets bootstrapped.
Actual: a blank screen with no error thrown.
UPDATE Issue was these lines:
optimization:
{
splitChunks: {
chunks: 'all'
}
}
Optimization was causing this issue, once I removed above config option from webpack, application at least starting bootstrapping, though this time I'm getting error like:
Uncaught Error: Can't resolve all parameters for ApplicationModule: (?).
at syntaxError (compiler.js:2547)
at CompileMetadataResolver../node_modules/#angular/compiler/fesm5/compiler.js.CompileMetadataResolver._getDependenciesMetadata (compiler.js:17874)
at CompileMetadataResolver../node_modules/#angular/compiler/fesm5/compiler.js.CompileMetadataResolver._getTypeMetadata (compiler.js:17767)
at CompileMetadataResolver../node_modules/#angular/compiler/fesm5/compiler.js.CompileMetadataResolver.getNgModuleMetadata (compiler.js:17635)
at CompileMetadataResolver../node_modules/#angular/compiler/fesm5/compiler.js.CompileMetadataResolver.getNgModuleSummary (compiler.js:17445)
at compiler.js:17559
at Array.forEach (<anonymous>)
at CompileMetadataResolver../node_modules/#angular/compiler/fesm5/compiler.js.CompileMetadataResolver.getNgModuleMetadata (compiler.js:17547)
at CompileMetadataResolver../node_modules/#angular/compiler/fesm5/compiler.js.CompileMetadataResolver.getNgModuleSummary (compiler.js:17445)
at compiler.js:17532
I tried to fix this by adding polyfills.ts file in my project
Polyfills.ts
import 'core-js/es7/reflect';
import 'core-js/client/shim';
import 'zone.js/dist/zone.js';
but still getting same error, I'm using core-js 3.2.1.
looking if someone have idea about what's going wrong with my code?
UPDATE I learned that I supposed to add polyfills.ts file in HtmlWebpackPlugin-->chunks array as well, after adding, it started picking polyfills file and now that error has gone and now my angularjs app also getting bootstrapped along side angular 7 app, however now I'm getting another error like:
Error: [$injector:modulerr] Failed to instantiate module $$UpgradeModule due to:
Error: [$injector:modulerr] Failed to instantiate module {"default":"ui.app"} due to:
Error: [ng:areq] Argument 'module' is not a function, got Object
https://errors.angularjs.org/1.6.10/$injector/modulerr?p0=%24%24UpgradeModule&p1=Error%3A%20%5B%24injector%3Amodulerr%5D%20Failed%20to%20instantiate%20module%20%7B%22default%22%3A%22ec.customer.servicing.ui.app%22%7D%20due%20to%3A%0AError%3A%20%5Bng%3Aareq%5D%20Argument%20'module'%20is%20not%20a%20function%2C%20got%20Object%0A%0Ahttps%3A%2F%2Ferrors.angularjs.org%2F1.6.10%2F%24injector%2Fmodulerr%3Fp0%3D%257B%2522default%2522%253A%2522ec.customer.servicing.ui.app%2522%257D%26p1%3DError%253A%2520%255Bng%253Aareq%255D%2520Argument%2520'module'%2520is%2520not%2520a%2520function%252C%2520got%2520Object%250Ahttps%253A%252F%252Ferrors.angularjs.org%252F1.6.10%252Fng%252Fareq%253Fp0%253Dmodule%2526p1%253Dnot%252520a%252520function%25252C%252520got%252520Object%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A32020%253A12%250A%2520%2520%2520%2520at%2520assertArg%2520(http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A33994%253A11)%250A%2520%2520%2520%2520at%2520assertArgFn%2520(http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A34004%253A3)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A36915%253A11%250A%2520%2520%2520%2520at%2520forEach%2520(http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A32313%253A20)%250A%2520%2520%2520%2520at%2520loadModules%2520(http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A36889%253A5)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A36907%253A40%250A%2520%2520%2520%2520at%2520forEach%2520(http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A32313%253A20)%250A%2520%2520%2520%2520at%2520loadModules%2520(http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A36889%253A5)%250A%2520%2520%2520%2520at%2520createInjector%2520(http%253A%252F%252Flocalhost%253A8080%252Fng1.bundle.js%253F29bb21d813a74a626d53%253A36806%253A19)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A32020%3A12%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A36929%3A15%0A%20%20%20%20at%20forEach%20(http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A32313%3A20)%0A%20%20%20%20at%20loadModules%20(http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A36889%3A5)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A36907%3A40%0A%20%20%20%20at%20forEach%20(http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A32313%3A20)%0A%20%20%20%20at%20loadModules%20(http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A36889%3A5)%0A%20%20%20%20at%20createInjector%20(http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A36806%3A19)%0A%20%20%20%20at%20doBootstrap%20(http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A33860%3A20)%0A%20%20%20%20at%20Object.bootstrap%20(http%3A%2F%2Flocalhost%3A8080%2Fng1.bundle.js%3F29bb21d813a74a626d53%3A33881%3A12)
at angular.js:125
at angular.js:5034
at forEach (angular.js:418)
at loadModules (angular.js:4994)
at createInjector (angular.js:4911)
at doBootstrap (angular.js:1965)
at Object.bootstrap (angular.js:1986)
at bootstrap (static.js:76)
at static.js:1595
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
Any idea what's going wrong here?
If you're migrating from AngularJS probably the <script> tag for your bundle is inside the head segment. Move it to the end of body
<html>
<head>
</head>
<body>
... ...
<script src="dist/main.js" charset="utf-8"></script>
</body>
</html>

AngularJs Multiple Times loaded

I have a problem with upgrade my angularJs Application to Webpack4.
this is my setup:
vendor.ts
import "angular";
import "angular-i18n/de-de";
import "angular-route";
and
main.ts
import {MyAppModule} from "./my-app.app";
angular.element(document).ready(() => {
angular.bootstrap(document.body, [MyAppModule.name], { strictDi: true });
});
With webpack 3. I had a commonsChunkPlugin and everything worked.
With webpack 4, I'm using the splitChunks option to not import angularjs 5 times:
webpack.config.ts
...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "commons",
chunks: "initial",
minChunks: 2
}
}
}
}
...
That is working correctly. I have loaded the angularjs code only in my common.js file. But unfortunatelly the code is instantiated twice, so the app always logs the warning:
WARNING: Tried to load AngularJS more than once.
The chunks are loaded via HtmlWebpackPlugin in the html.
Any idea how to remove the warning?
Found the solution in the deeps of github issues:
The vendor file should not be an entry point but the entry point should be a list of files:
...
entry: {
main: ['./vendor.js', './main.js']
},
...

How to reference a NodeJS module w/ Webpack

When using SystemJS for writing an Angular2 app I can do a
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'#angular': 'node_modules/#angular',
'rxjs': 'node_modules/rxjs'
};
to tell angular where to find things when I call a import {} from. In this case if I wanted to use RxJS now I could import { Observable } from 'rxjs/Rx'.
But what would the equivalent of this be if I were using Webpack?
Webpack does that automatically. Unless you are using code splitting.
Suppose you have:
Module A:
import {fn} "moduleB"
Module B:
export default fn
Webpack will include all the dependencies of module A (your entry), so you will be able to use fn.
Now if you use code splitting, you will need to use require.ensure
e.g:
require.ensure(["module-a", "module-b"], function(require) {
var a = require("module-a");
// ...
});

AngularJS 1 to Angular 2 Upgrade Strategy

I decide to prepare updating my application from angular1.x to angular2.x. There is I have no find something useful. I have studied this document about 1 to 2 upgrade strategy. I figured out that all magic in migration is that you have to start Angular 1 and 2 in one time with Angular 1 in the root of the application, cut off the Angular1 unsupported code(filters, decorators and etc) and adapt(read wrap!) all Angular1 supported code(directives, services and etc).
The document that I have given above, you can see the pseudo code of the wrappers. I think if I wrap all of my current code - it doesn't explicitly give it speed. Who really have experience about it, write please how is it in real? Can I feared that my application starts to slow down, and may be easier to rewrite it once a new Angular2? But it`s very big, it will be a big piece of work and I have to think before. That why I ask about real experience who have production real life big projects and already migrated.
Also, I want to ask how I check libraries compatibilities. Maybe there is some service that checks my app and output results what libraries are good and what fails?
Yes, You can use both Angular 1 & Angular 2 in the same application. Just follow the below steps:
First of all you need to create "package.json" with all required angular 2 dependencies + #angular/upgrade
Create "tsconfig.json" and set "module": "system" in "compilerOptions" object. (To avoid require js errors)
Create "system.config.js" file (you can copy this file from angular 2 quick-start repo.). Don't forget to add '#angular/upgrade/static': 'npm:#angular/upgrade/bundles/upgrade-static.umd.js' bundle in a map object.
Include JS files for Reflect.js, zone.js, and system.config.js in your index.html just before the </body> tag (To avoid reflect-metadata & zone js errors).
Add this code just below that to import your app:
<script type="text/javascript">
System.import('app').catch(function(error){
console.log(error);
});
</script>
Create "main.ts" file and add below code :
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { UpgradeModule } from '#angular/upgrade/static';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { downgradeComponent } from '#angular/upgrade/static';
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['<app-name>']);
});
angular.module('<app-name>', []).directive('angular2App',
downgradeComponent({component: AppComponent}) as angular.IDirectiveFactory);
Create "app.module.ts" file and add the below code:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { UpgradeModule } from '#angular/upgrade/static';
import { AppComponent } from './app.component';
#NgModule({imports: [BrowserModule,UpgradeModule],declarations: [AppComponent],entryComponents: [AppComponent]})
export class AppModule {ngDoBootstrap() {console.log("Bootstrap Angular 2");}}
Create "app.component.ts" file and add below code":
import { Component } from '#angular/core';
#Component({selector: 'angular2',template: '<h1>Angular 2 Component</h1>'})
export class AppComponent { }
Now add the below code in your Angular 1 view file :
<angular2-app>Loading Angular 2...</angular2-app>
That's it. :)

Resources