ASP.NET Core - Running mutiple angular 2 applications - javascript

I'm facing some problems while trying to run multiple angular 2 application with ASP.NET Core. I'm using
JavaScriptServices with prerendering feature
in a Visual Studio 2015 template.
The structure of my solution is here.
The Core contians the ASP.NET application with server-side routing, and each ClientApp, once boundled, is copied inside the wwwroot.
The problem here is the prerendering feature, which rises:
Prerendering failed because of error: Error: Zone already loaded.
This happens when, after the first render of ClientApp1 I reload the page or when i try to switch between ClientApp1 and ClientApp2.
Can someone help me suggesting what is proper way to run multiple Angular2 applications using boot-server and boot-client style?
Any example/suggestion will be appreciated.
The issue is opened also in github at github.com/aspnet/JavaScriptServices/issues/566

The approach I'm using that seems to work is to simply define multiple entry points in webpack config.
const clientBundleConfig = {
entry: {
'front': './client/front/main.ts',
'admin': './client/admin/main.ts',
},
output: {
path: './www/dist',
filename: '[name].bundle.js'
}
...
}
Now the relevant angular app front or admin will update from a single HMR process. I couldn't get it to work with separate webpack config and HMR processes using the same dotnet server process, I found only the first app would update.
Update
I needed to perform a separate build for apps due to restrictions I ran into. I now follow SteveSandersonMS suggestion of calling UseWebpackDevMiddleware for each app in the Github issue you linked to, the only step missing from his suggestion is the need to specify a unique endpoint for each app:
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ConfigFile = "webpack.front.js",
HotModuleReplacementEndpoint = "/__webpack_hmr_front"
});
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ConfigFile = "webpack.admin.js",
HotModuleReplacementEndpoint = "/__webpack_hmr_admin"
});

Related

Can web workers have access to classes defined in Vue application?

I’m building an application that uses Vue for our front-end, specifically Vue 3 Composition API + Typescript. I need the ability to use web workers for long running processes in the background. I was able to get a vanillajs web worker to run alongside the Vue application no problem. My issue is that I need my web worker to have access to classes and functions that are written inside the Vue app. Both my web worker and my Vue app need to use the same classes and functions and I don’t want to have to write them in two places. Is there a way to share them? Any help is appreciated.
The answer is yes:
There is a way to let the web worker having access to the Vue.js framework through one single JavaScript file.
The library that will help you with this in your Vue.js project is vue-worker. This library uses the simple-web-worker package. (Inline Web Workers approach)
As you may know, a standard web worker requires an extra js file that will contain the code of the worker. For inline web workers it isn't necessary to use a helper method. That will inject a property into Vue (and pass it to every child component), with a default name of $worker. In total you can say it is behaving as an JavaScript promise but without really being a second JavaScript file.
Now your turn:
There is a really good documentation to follow along with this approach I described and additional a second "old-fashion" way. Try it out :)
I was able to figure out a solution using esbuild. I added a process to my npm run serve and npm run build commands so it runs node ./esbuild.js before the vue-cli commands. This compiles my typescript web worker to javascript and puts it in the public folder before compiling the Vue app. Now I can create a web worker like normal using:
const worker = new Worker('/worker.js', { type: 'module' })
And here is my esbuild.js file:
const esbuild = require('esbuild')
const { nodeExternalsPlugin } = require('esbuild-node-externals')
const config = {
entryPoints: ['./src/workers/worker.ts'],
outfile: 'public/worker.js',
bundle: true,
minify: false,
plugins: [nodeExternalsPlugin()]
}
esbuild.build(config).catch(() => process.exit(1))

Combining Static Sites + Client Side Rendering (React, Gatsby)

I want to build a web app with React.
When users visit the site, they will see a Landing Page, can go to a Pricing Page, an About page, a Blog. etc. They can also Sign Up or Log in and then there's the actual app. I would like render certain pages (Landing,Pricing,About,Blog) statically, but would like to leave everything behind the SignUp/Login-Wall client-side rendered.
(First, because it cannot be static, since this is dynamic content. And also, because I do not care about SEO here anyways, so a major reason for next.js falls away, since the app is behind a SignUp/Login Wall anyways.)
Questions: First of all: Does this make sense? And secondly: How could I implement something like this? I haven't found anything online! Is this unheard of? I would like to use Gatsby.js for my static content, but I am not sure how to bring the client-side-rendered bit into the mix. I have worked with create-react-app before, which does client-side-rendering, - but I am not sure how I would go about the implementation?
I will try to explain the process behind jamstack-hackathon-starter (which #ksav commented).
It is a starter template for gatsby that allows you to save static pages in-
conjunction with dynamic pages (client-side react app) - a "Hybrid Gatbsy App".
Manual Steps:
1. Create a folder src/app which will contain your client-side react app.
2. Create a file in src/pages called app.js, with the following contents:
// I'm using create-react-app's structure
import App from '../app/src/App' // make sure this path corresponds to your path
export default App
Now install gatsby-plugin-create-client-paths:
npm install --save gatsby-plugin-create-client-paths
Configure it by adding it to gatsby-config.js like so:
plugins: [
{
resolve: `gatsby-plugin-create-client-paths`,
options: { prefixes: [`/app/*`] },
},
...
This will result in everything within /app to only be rendered in the browser (ie client-side).
Go to your browser after building (gatsby develop) and check /app
According to npmjs
The plugin gatsby-plugin-create-client-paths is deprecated.
https://www.npmjs.com/package/gatsby-plugin-create-client-paths
This plugin's functionality is now built-in to Gatsby.
Use the File System Route API: https://gatsby.dev/creating-client-only-routes.
This package will no longer receive updates.

Angular CLI 6: How to consume a library sub-project in the main application?

I've got an Angular 6 project that's made of up a main application, and a separate sub-project that is a library. I'm trying to consume this library from the main application, and I can't seem to get it working.
In the tsconfig.json, I have the following paths configuration:
"paths": {
"#my-company/my-package/*": "dist/my-package/*"
}
And then in the main app, I import the library like so:
import { ButtonModule } from '#my-company/my-package/button';
However, when I build the main application, I get tons of errors about not being able to find modules. For the above import statement, I'll get this error:
Module not found: Error: Can't resolve '/Users/jattardi/code/myproject/dist/my-package/button'
However, if I check the dist/my-package directory, there certainly is a button directory containing the type definitions.
The reason my imports have subpaths, e.g. #my-company/my-package/button instead of just #my-company/my-package is to make it tree-shakeable. Not sure this is possible. Since this is an Angular 6/ng-packagr generated build, do I lose this ability?
I was hit with the same error when trying to consume in the main application. My answer will not solve that case as I am trying to get my lazy loaded module, I moved into the new Angular6 library, to work.
I was able to publish my library project to npm and consume it in the main application as an npm dependency. For eg: #santony/ngx-material. May be as a workaround you could do that until this is resolved.
For those who are still facing this problem, there's a "how to" at ng-packagr's documentation:
https://github.com/ng-packagr/ng-packagr/blob/master/docs/secondary-entrypoints.md
Basically,
All you have to do is create a package.json file and put it where you want a secondary entry point to be created.
The contents of my_package/testing/package.json can be as simple as:
{
"ngPackage": {}
}
And also, in dev application, I've added the path reference to the secondary endpoint, so it worked:
"#my-company/my-library/another": [
"dist/my-library/another"
]

How can I improve load performance of Angular2 apps?

Angular2 app is loading slow, how can I improve the performance on load?
I use Angular2, typescript with html5.
currently my app takes 4 seconds to load.
I host with Firebase and use cloudflare.
Things I'm doing / info:
I've compressed images.
I minify css
I minify js.
I use async on my scripts.
My scripts are in my .
The scripts are around 700kb
I used google speed test and get 65%
I used minified version of the libs I use e.g. bootstrap etc.
Using systemjs.
This is the seed app im using: https://github.com/mgechev/angular-seed
Flow:
When the app loads it shows a blue screen (this is the bootstrap css) and then 4 seconds later the app loads and works really fast. But takes 4 seconds to load. It seems the app.js file that systemjs minifies to is slowing the whole app, and not showing the views fast enough.
This is my website speed test:
https://www.webpagetest.org/result/161206_F5_N87/
This is my website:
https://thepoolcover.co.uk/
Let me know if you need more information about my app and any other things I can do.
A single page application generally takes more time while loading as it loads all necessary things at once.
I had also faced same problem and my team has optimized our project from loading in 8 seconds to 2 seconds by using following methods.
Lazy loading a module : Lazy loading modules helps to decrease the startup time. With lazy loading our application does not need to load everything at once, it only needs to load what the user expects to see when the app first loads. Modules that are lazily loaded will only be loaded when the user navigates to their routes. Angular2 has introduced modules in its final release RC5. See below for step-by-step guide.
Aot Compilation : With AoT, the browser downloads a pre-compiled version of the application. The browser loads executable code so it can render the application immediately, without waiting to compile the app first.
It reduces the payload size : There's no need to download the Angular compiler if the app is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload. For more info see this.
Webpack : Webpack is a popular module bundler, a tool for bundling application source code in convenient chunks and for loading that code from a server into a browser. You can configure your Angular 2 web application with webpack (see this guide).
Remove scripts,stylesheet from index.html : Remove all scripts and stylesheet which are not needed in index.html. You can load these script dynamically in component itself by calling a service.
Make a file script.service.ts which can load any script on demand for that component
\script.service.ts
import { Injectable } from '#angular/core';
declare var document: any;
#Injectable()
export class Script {
loadScript(path: string) {
//load script
return new Promise((resolve, reject) => {
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = path;
if (script.readyState) { //IE
script.onreadystatechange = () => {
if (script.readyState === "loaded" || script.readyState === "complete") {
script.onreadystatechange = null;
resolve({ loaded: true, status: 'Loaded' });
}
};
} else { //Others
script.onload = () => {
resolve({ loaded: true, status: 'Loaded' });
};
};
script.onerror = (error: any) => resolve({ loaded: false, status: 'Loaded' });
document.getElementsByTagName('head')[0].appendChild(script);
});
}
}
This is just a sample code to load script dynamically, you can customize and optimize it by yourself according to your need.
For stylesheet you should load it in component using styleUrl.
Use Browser Caching : Your webpage files will get stored in the browser cache when you use browser caching. Your pages will load much faster for repeat visitors and so will other pages that share those same resources. For more info https://varvy.com/pagespeed/leverage-browser-caching.html
minimize the code in app.component.ts : minimize the code present in app.component.ts which always run when the app loads or reloads.
set data on app Initialization : if you are using same api calls multiple times in your project or in components,
or you are dependent upon same data in multiple component, instead of calling api multiple times what you can do is save
the data as an object in service on app initialization. That service will act as a singleton throughout the project and you
can access that data without calling api.
Lazy loading of modules step by step
Modular structure : We have to divide our App into separate modules. For example an app may have a user side and an admin side and each will have its own different components and routes, so we will separate this two sides into modules admin.module.ts and user.module.ts.
Root Module : Every Angular app has a root module class. By convention it's a class called AppModule in a file named app.module.ts , this module will import the above two module and also the AppComponent for bootstrap. You can also declare multiple components according to your need. Sample code in app.module.ts:
\app.module.ts
import { NgModule } from '#angular/core';
import { UserModule } from './user/user.module';
import { AdminModule } from './admin/admin.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login.component';
#NgModule({
imports: [UserModule, AdminModule],
declarations: [AppComponent, LoginComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
Routes : Now in your routes you can specify like the following
\app.router.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { LoginComponent } from './login.component';
const routes: Routes = [
{ path: 'login', component: 'LoginComponent' }, //eager loaded
{ path: 'admin', loadChildren: './admin/admin.module#AdminModule' }, // Lazy loaded module
{ path: 'user', loadChildren: './user/user.module#UserModule' } //lazy loaded module
];
Now when the application loads, it will only load LoginComponent and AppComponent code. These modules will only be loaded when we visit /admin or /user routes. Hence it will decrease the size of payload for loading into the browser, thus resulting in fast loading.
Nesting Modules : Just like app.module every module has its own set of components and routes. As your project becomes larger, the nesting of modules inside module is the best way to optimize because we can lazily load those modules whenever we require.
PLEASE NOTE
Above code is only for explanation, please refer for full example
https://angular-2-training-book.rangle.io/handout/modules/lazy-loading-module.html
How about "code splitting".
From the Webpack site:
"For big web apps it’s not efficient to put all code into a single file, especially if some blocks of code are only required under some circumstances. Webpack has a feature to split your codebase into “chunks” which are loaded on demand. Some other bundlers call them “layers”, “rollups”, or “fragments”. This feature is called “code splitting”.
Link here:
https://webpack.github.io/docs/code-splitting.html
Note that the Angular CLI uses Webpack.
Also, make sure that if your app bootstraps with data calls, that you are not holding up the rendering of your components waiting on those calls to return. Promises, async, etc.
It is difficult to diagnose the precise problem you are having without hands-on to your entire code base and backend (as others have suggested, the problem may not be angular at all).
Having said that, I HIGHLY recommend you start using the angular-cli. It was designed by the angular team to accomplish all of the things you need to do in a easy-to-use command line interface. So my answer is predicated on the use of the angular-cli.
Here are the general things you can do to optimize your ng2 project for production:
1) Ahead of Time (AoT) Compilation - Bundling/Minification/Tree-shaking
Look, forget about the headache of configuring a bunch of gulp tasks to accomplish all of these things. The angular-cli handles Bundling/Minification/Tree-shaking/AOT compilation in one easy step:
ng build -prod -aot
This will produce the following js files in your "dist" folder:
inline.d41d8cd98f00b204e980.bundle.js
vendor.d41d8cd98f00b204e980.bundle.js
main.d41d8cd98f00b204e980.bundle.js
styles.4cec2bc5d44c66b4929ab2bb9c4d8efa.bundle.css
You will also get the gzipped versions of these files for MORE optimization:
inline.d41d8cd98f00b204e980.bundle.js.gz
vendor.d41d8cd98f00b204e980.bundle.js.gz
main.d41d8cd98f00b204e980.bundle.js.gz
Angular's AOT compilation will automatically do "tree shaking" on your code and get rid of any unused references. For example, you may use lodash in your project, but you probably only use a few lodash functions; tree shaking will trim away all the unused parts of lodash that are not needed in your final build. And most importantly, AOT compilation will pre-compile all of your code and views which means LESS time the browser needs to get the ng2 app rolling. Click here for more info on angular's AOT compilation.
2) Lazy loading parts of your app
If you further carve up your app into different parts, you do not need to load EVERYING when your app first loads. You can specify different modules for your application that then can be bundled (by the angular-cli aot compiler) into different chunks. Read up here to learn how to organize your project into modules that you can compile into chucks that are only loaded AS NEEDED. Angular-cli will manage the creation of these chunks for you.
3) Angular Universal
Now if you really want to make your load time EXTREMELY fast then you will want to consider implementing Angular Universal, which is when you compile your initial view ON THE SERVER. I have not used Angular Universal as I have been able to achieve fast load times with steps 1 and 2. But it is an exciting option in the ng2 toolset. Keep in mind you don't compile or run the ng2 app on the server, you compile the initial view serverside so the user quickly receives a jolt of html and thus the user PERCEIVES the load time to be very fast (even though a full load will still lag behind a little bit). This step does not obviate the need for the other steps. As a bonus, Angular Universal also is supposed to help with SEO.
4) Secondary bundling
If I am not using lazy loading, I usually go ahead and further bundle the distribution files that are generated from AOT compilation. Thus I create one main.bundle.js file that concats inline.js, vendor.js and main.js files. I use gulp for this.
because its SPA and angular 2 init too slow. thats it. plus RXjs, tons of polifills etc. AOT can help but a lot of angular2 libs do not work with it. angular universal realy helps
Build your angular app using following command to get maximum optimization benefits.
ng build --prod --aot --optimization --build-optimizer --vendor-chunk --common-chunk --extract-licenses --extract-css --source-map=false
Basically you will build in aot mode and use treeshaking with some optimization.
optimization: Enables optimization of the build output.
vendor-chunk: Use a separate bundle containing only vendor libraries.
common-chunk: Use a separate bundle containing code used across multiple bundles.
extract-css: Extract css from global styles onto css files instead of js ones.
build-optimizer: Enables #angular-devkit/build-optimizer optimizations when using the 'aot' option.
source-map=false: remove source map will also reduce bundle size
Try disabling source maps by running ng serve --sourcemap=false

How to handle window object on nodejs for server-side rendering of reactjs application

I am trying to implement server-side rendering for my reactjs application.
I am using webpack to build reactjs application, enhanced-resolve to handle importing of jsx files in nodejs.
My application depends on third party libraries like enquire.js.
When react application tries to import enquire.js on nodejs, it fails with error
ReferenceError: window is not defined
Since window object is not available nodejs
how to handle libraries that use window for server side rendering ?
I haven't used Webpack yet. However, I had similar issue using browserify and I solved it by creating two builds: one for browser one for node.js with list of modules to ignore. You could achieve the same effect by adding to webpack config:
{
plugins: [
new webpack.IgnorePlugin(/file\.js$/)
]
}
Then you have to make sure that you are not making any calls to enquire.js by checking if require() returned false value or object with module functions.
Well this is quite old question still if some one is looking at it.
Try
if (typeof window === 'undefined') {
global.window = {};
}

Categories

Resources