How could I use a system.import() into component angular 2 - javascript

I saw in this post that you can use SystemJS to load external javascript files into my components in Angular 2.
In my index.html :
<script>
System.config({
packages: {
"frontOfficeA2/src": {
format: 'register',
defaultExtension: 'js'
},
"angular2-jwt": {
"defaultExtension": "js"
},
"ng2-bootstrap": {
"defaultExtension": "js"
},
"system": {
"defaultExtension": "js"
}
},
map: {
"angular2-jwt": "lib/angular2-jwt",
"ng2-bootstrap": "lib/ng2-bootstrap",
"moment": 'lib/moment/moment.js',
"system": 'lib/systemjs/dist/system.src.js'
}
});
System.import('frontOfficeA2/src/app.js').then(null, console.error.bind(console));
</script>
And my component :
import {Component} from 'angular2/core';
import { DATEPICKER_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { System } from 'system';
#Component({
selector: 'main',
templateUrl: 'app/components/main/main.html',
styleUrls: ['app/components/main/main.css'],
providers: [],
directives: [DATEPICKER_DIRECTIVES],
pipes: []
})
export class Main {
date: Date = new Date();
constructor() {
System.import('path/to/your/file').then(refToLoadedScript => {
refToLoadedScript.someFunction();
});
}
}
Finally, when I start my app :
frontOfficeA2/src/app/components/main/main.ts(3,24): error TS2307: Cannot find module 'system'.
If somebody have an idea of what am I doing wrong .. :)
Thanks :)

In fact, SystemJS is used under the hood when you import things. It's because you configured your TypeScript compiler to use it. See the tsconfig.json file:
{
"compilerOptions": {
"target": "ES5",
"module": "system", <---------------
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules"
]
}
If you have a look at compiled JS files (these JS files are actually executed in the browser), you will see this:
System.register(['angular2/platform/browser', 'angular2/http', './app.component'], function(exports_1) {
var browser_1, http_1, app_component_1;
return {
setters:[
function (browser_1_1) {
browser_1 = browser_1_1;
},
function (http_1_1) {
http_1 = http_1_1;
},
function (app_component_1_1) {
app_component_1 = app_component_1_1;
}],
execute: function() {
browser_1.bootstrap(app_component_1.AppComponent, [http_1.HTTP_PROVIDERS]).then(function (componentRef) {
console.log(componentRef.injector);
});
}
}
});
for a TypeScript file like this:
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {AppComponent} from './app.component';
bootstrap(AppComponent, [ HTTP_PROVIDERS ]).then((componentRef) => {
console.log(componentRef.injector);
});

You can use systemjs to do your external dependency loading.
npm i systemjs --save-dev
npm i #types/systemjs --save-dev
You'll need to update your tsconfig.app.json file (tsconfig.json file for older versions of Angular).
"types": ["systemjs"]
Now you'll be able to import
System.import("your-url").then(response => response.methodCall());
If you have an import map specified
<script type="systemjs-importmap">
{
"imports": {
"import-name": "external-code-url",
}
}
</script>
You can instead call this code
System.import("import-name").then(response => responce.methodCall());

Related

jsconfig path alias is not working Sveltekit

I am using svelte kit (with typescript) and have some created some shortlinks and cannot get the new link "$base" to work. I added the shortlink here
./jsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"baseUrl": ".",
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"],
"$base": ["src/baseApp"],
"$base/*":["src/baseApp/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
}
The is also no intellisense
More details about jsconfig.json here
I also found something about a similar issue with NEXT here
I tried this and it didn't work
In addition to jsconfig.json I tried adding my the paths to my tsconfig.json file also
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
},
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"],
"Base": ["src/baseApp"],
"Base/*":["src/baseApp/*"]
}
}
Try adding your paths to the svelte.config.js file in the root of your project
...
import path from 'path';
/** #type {import('#sveltejs/kit').Config} */
const config = {
...
kit: {
...
vite: {
resolve: {
alias: {
$lib: path.resolve('./src/lib'),
$base: path.resolve('./src/baseApp'),
}
}
}
}
};
export default config;
Edit: Newer versions of sveltekit uses vite.config.js instead
import { sveltekit } from '#sveltejs/kit/vite';
import path from "path"
const config = {
resolve: {
alias: {
'$lib': path.resolve('./src/lib/'),
'$base': path.resolve('./src/baseApp'),
},
},
plugins: [sveltekit()]
};
export default config;
This is the latest way of implementing it. No need for vite config file
https://kit.svelte.dev/docs/configuration#alias
//svelte.config.js
import path from 'path';
const config = {
...
kit: {
...
alias: {
$components: path.resolve('./src/components')
}
}
};

Typescript library to single global javascript file

I'm writing a Typescript library with this structure:
and file contents:
restApi.class.ts
import { restApiOptions } from '../models/rest.options.model';
import { StoreMethods } from '../routes/store.methods.class';
import { UserMethods } from '../routes/user.methods.class';
export class RestApi {
public storeRest: StoreMethods;
public userRest: UserMethods;
constructor(private restApiOptions: restApiOptions) {
.....
}
setLanguage(langId: number){
.....
}
}
store.methodds.class.ts
import { Observable } from 'rxjs';
import { restApiOptions } from '../models/rest.options.model';
import { routeMethods } from '../core/routeMethods.interface';
export class StoreMethods implements routeMethods {
constructor(private restApiOptions: restApiOptions) {
.....
}
setLanguage(languageId: number){
......
}
getStore(storeId: number): Observable<any> {
.....
}
}
and public_api.ts
export { RestApi } from './lib/core/restApi.class'
the library is intended to be used as a dependency in an Angular2+ project, so i have a tsconfig file with the next configuration to transpile it and generate definition files
{
"compilerOptions": {
"outDir": "./dist/",
"declaration": true,
"module": "commonjs",
"target": "es5",
"lib": [
"es2017",
"dom",
"es2015",
"es5",
"es6"
]
},
"exclude": [
"node_modules",
]
}
The problem i have is that this library also needs to be used in a plain es5 javascript project in an "old fashioned way", that is, including the javascript library file in a script tag and using it in a way like this:
var myRestApi = new RestApi(options)
I'm using webpack to combine all files into a single bundle.js file but after generating this file and including it in the project I don't have access to the RespApi class.
this is my webpack.config.js
const path = require('path');
module.exports = [{
entry: './src/public_api.ts',
module: {
rules: [{
test: /\.tsx?$/,
use: [{
loader : 'ts-loader',
options:{
configFile : 'tsconfig.json'
}
}],
exclude: /node_modules/
}]
},
resolve: {
extensions: ['.ts', '.js', '.tsx']
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dev')
}
}];
is there a way to transpile the library into a single javascript file and accessing the RestApi class from global??
There's an official guide on webpack's site. I recommend you read it.
Here's the cheatsheet. Add two fields to your webpack.config.js.
webpackConfig.output.library = "RestApi"
webpackConfig.output.libraryTarget = "var"
There's a short coming though. Because you export your module as a named module in public_api.js, user can only access it through window.RestApi.RestApi. Without experimenting, I'm not entirely sure how to solve this.

Include es5 lib into the stencil web component

I have an external library that is written in the old IIFE style. I have a web component which uses this lib inside. This web component was created with stencil.
Now if I use my web component in some project, I have to include component js file and this external library to the index.html via src file. How can I include this library to the component's compiled code? Is it possible without re-writing it to the es6 module?
This is how my code looks now (in the index.html):
<script src="./myMathLib.js"></script>
<script src="./myWebComponent.js"></script>
I want to have it like this:
<script src="./myWebComponent.js"></script>
This is the code of my component:
import {Component, Prop} from '#stencil/core';
declare var myMathLib: any;
#Component({
tag: 'my-component',
shadow: true
})
export class MyComponent {
#Prop() name: string;
#Prop() age: number;
render() {
return <div>
The age of {this.name} is: {myMathLib.calculate(this.age)}
</div>;
}
}
This is my tsconfig.json:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"declaration": false,
"experimentalDecorators": true,
"lib": [
"dom",
"es2017"
],
"moduleResolution": "node",
"module": "esnext",
"target": "es2017",
"noUnusedLocals": true,
"noUnusedParameters": true,
"jsx": "react",
"jsxFactory": "h"
},
"include": [
"src",
"types/jsx.d.ts"
],
"exclude": [
"node_modules"
]
}
This is my stencil.config.ts:
import { Config } from '#stencil/core';
export const config: Config = {
namespace: 'mycomponent',
outputTargets:[
{ type: 'dist' },
{ type: 'docs' },
{
type: 'www',
serviceWorker: null // disable service workers
}
]
};
Somewhere in the root of your project, there should be a stencil.config.ts file. In there you can specify copy tasks. You can read here how to do this: https://stenciljs.com/docs/config#copy
After you set that up correctly and your ../assets/ folder is being copied to your build folder.
You need to copy your all the external js file inside assets folder.
In your render method you can directly refer js file from /assets/
After some research, I figured out that the best option is to use globalScript property from stencil.config.
I added my library to the assets folder and then added the following line to my stencil.config.ts file:
globalScript:'src/assets/myMathLib.js'
After it, I was able to use myMathLib.calculate(this.age) in the code of the component.

Upgrading AngularJS to Angular, AppModule was bootstrapped, but it does not declare "#NgModule.bootstrap" Error

I'm currently experimenting with upgrading an AngularJS app to Angular. Been following along the tutorial on Angular.io. There are a few differences between that project and mine. I'm using RequireJS, Gulp and Webpack.
My index.html asks for requireJS/main.js, main.js starts
The first step I'm trying to get working is to bootstrap a hybrid application with NgUpgrade.
What I've tried so far from google searching is tweak the tsconfig, changing around to different version of zone.js, re-configuring around the order of things loading.
The error that I can't seem to resolve or find any resolutions to on the internet is:
Error: Uncaught (in promise): Error: The module AppModule was bootstrapped, but it does not declare "#NgModule.bootstrap" components nor a "ngDoBootstrap" method. Please define one of these.
Here is my tsconfig.json
{
"compilerOptions": {
"module": "amd",
"moduleResolution": "node",
"sourceMap": true,
"declaration":false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2017", "dom" ],
"typeRoots":["node_modules/#types"]
},
"include:":["./src/s/**/*"],
"exclude": [
"node_modules","sandbox","gulp-tasks","dist","3rdparty",".settings"
]
}
Here is my main.js which is just the requirejs config:
require.config({
waitSeconds : 0,
baseUrl: './s/lib',
paths: {
'app': 'app',
'angular': 'angular',
'angular-aria': 'angular-aria.min',
'jquery': 'jquery.min'
"wa-angular": "wa-angular.min",
'ui.router.components': 'routeToComponents',
'reflect-metadata':'Reflect',
'zone.js':'zone.js/dist/zone',
'rxjs':'rxjs',
'#angular/common':'common.umd',
'#angular/compiler':'compiler.umd',
'#angular/core':'core.umd',
'#angular/upgrade':'upgrade/upgrade.umd',
'#angular/upgrade/static':'upgrade/upgrade-static.umd',
'#angular/platform-browser-dynamic':'platform-browser-dynamic.umd',
'#angular/platform-browser':'platform-browser.umd'
},
shim: {
'angular': {'exports': 'angular'}
},
priority: [
'angular'
],
packages: [
],
deps: ['app']
});
Here is my app.js
"use strict";
var $ = window.$;
define(["angular"], function(angular) {
require([
"jquery",
"angular-aria",
"wa-angular-module",
"ui.router.components",
"compiler.umd",
"core.umd",
"platform-browser.umd",
"platform-browser-dynamic.umd",
"upgrade.umd",
"upgrade-static.umd",
"reflect-metadata",
"app.module"
], function() {
require(["angular"], function(angular) {
var app = angular
.module(
"wa-module", [
"ngRoute",
"ngAria",
"ngMessages",
"ui.router",
"ui.router.components",
"ui.bootstrap",
"matchmedia-ng",
])
and finally, app.module.ts
import { NgModule } from "#angular/core";
import { BrowserModule } from "#angular/platform-browser";
import { UpgradeModule } from "#angular/upgrade/static";
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
#NgModule({
imports: [BrowserModule, UpgradeModule]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) {}
ngDoBootStrap() {
console.log("ngDoBootStrap running");
this.upgrade.bootstrap(document.body, ["wa"]);
}
}
platformBrowserDynamic().bootstrapModule(AppModule);
Please let me know what additional information you all might need to help me.
Thank you in advance.
Solution: ngDoBootstrap() is the correct way of spelling things.
I wrote it like ngDoBootStrap() and it couldn't resolve.
my bad.
(First time posting, sorry it's not thorough or well-formatted)
Not sure if this applies to the version of Angular at the time of the original post, but in Angular 9/10, it should work if you include a bootstrap list in app.module.ts.
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule, UpgradeModule],
bootstrap: [AppComponent]
})
Replace AppComponent with the appropriate overarching component for your application.
You have to change the code in main.ts file
Replace
platformBrowserDynamic().bootstrapModule(AppModule);
with
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
it may help to resolve your issue.

"Please add a #NgModule annotation" Error on Angular2

I have made a custom angular2(5.0.x) module that looks like this :
import { GuageService } from './services/guage.service';
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { GuageComponent } from './guage/guage.component';
#NgModule({
declarations: [GuageComponent],
imports: [
CommonModule
],
providers : [GuageService],
exports : [GuageComponent]
})
export class GuageModule {}
I use it in my app modules like this:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { DxButtonModule, DxCircularGaugeModule } from 'devextreme-angular';
import { GuageModule } from '#kronsbi/bi-module-template';
import { HttpClientModule } from '#angular/common/http';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
DxButtonModule,
DxCircularGaugeModule,
HttpClientModule,
GuageModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
When I try to start my app I get the following error.
Unexpected value 'GuageModule' imported by the module 'AppModule'. Please add a #NgModule annotation.
UPDATE
tsconfig for the main app:
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/#types"
],
"lib": [
"es2017",
"dom"
]
}
}
ts config for the GuageModule package:
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"stripInternal": true,
"experimentalDecorators": true,
"strictNullChecks": true,
"noImplicitAny": true,
"module": "es2015",
"moduleResolution": "node",
"paths": {
"#angular/core": ["node_modules/#angular/core"],
"rxjs/*": ["node_modules/rxjs/*"]
},
"rootDir": ".",
"outDir": "dist",
"sourceMap": true,
"inlineSources": true,
"target": "es5",
"skipLibCheck": true,
"lib": [
"es2017",
"dom"
]
},
"files": [
"index.ts"
],
"angularCompilerOptions": {
"strictMetadataEmit": true
}
}
If you are using Angular 5.0 you need to add "annotationsAs": "decorators" to the "angularCompilerOptions" for your package.
Angular 5 introduced new optimizations and by default the decorators are removed on compile because they are not needed at runtime. This does not work for packages as you already discovered. You can read about this in the Angular 5 announcement blog the "Build Optimizer" paragraph mentions this. Version 5.0.0 of Angular Now Available
I use this settings in my angular packages:
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"skipMetadataEmit": false,
"strictMetadataEmit": true,
"annotationsAs": "decorators"
}
I had the same problem. With angular 5+ and angular cli 1.5 it says that your code is not compatible and also your library is scoped package. I have managed to fix it with adding
export * from './your-path'
In all my files (exporting everything from my library).
As i understood its you import as 3 party library You can try to run the application with
ng serve --preserve-symlinks
also add flatModuleId in src/tsconfig.es5.json accordingly:
"flatModuleId": "#scope/library-name"
Link to github here
There is issue on github for more information
This is most likely an issue with the way your npm package is being created. In your package.json for your GuageModule are you defining a main? This should point to the entry point to your npm package. Here is an example of mine.
"main": "./dist/module.js",
Then if you want typings from GuageModule in your main app you'll need to go to your tsconfig.json and under compilerOptions set declaration to be true to generate the typings files.
"compilerOptions": {
...
"declaration": true
...
},
Then finally in your package.json you will need to point to the entry point for your typings file.
"types": "./src/app/layout.module.d.ts"
Now you should be able to import your module and have typings on the module that you imported. Hope this helps!
Please add "emitDecoratorMetadata": true in the compilerOptions of tsconfig.json of your gauge module

Categories

Resources