Is it possible to bootstrap NG2+ app manually from jquery / javascript code?
I need something like we do in TypeScript:
platformBrowserDynamic().bootstrapModule(AppModule);
The situation is being approached from wrong end.
In order to do that, platformBrowserDynamic and AppModule should be exposed to global scope, and they aren't. While it is possible to load Angular as UMD modules and have it as ng global, this would result in 2 copies of Angular, and AppModule would still be unreachable.
It's possible by exposing a function to global scope:
window.bootstrapApp = () => platformBrowserDynamic().bootstrapModule(AppModule);
But considering that the objective is to quickly check user permissions with non-Angular code, the right place to do this is still main.ts. And the preferable way to postpone application initialization is to do checks on bootstrap with APP_INITIALIZER provider.
Related
I have a file with defined interfaces I'd like to share with my app's global namespace. My first attempt to do this was that I imported the interfaces.ts file into my app.module.ts and placed the interface into the exports array, but types/interfaces cannot be used in this way, so I thought of a few questions related to this small issue.
Does app.module.ts need to be involved for exporting to the global namespaces?
Is there a different way to do it (probably a native javascript way)?
If app.module.ts is required to do this, how do I import an interface in a way that my app.module.ts shares it with the rest of my app, so that I wont have to constantly import it in my components?
Checkout the global namespace here: https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html
/*~ Note: If your global-modifying module is callable or constructable, you'll
*~ need to combine the patterns here with those in the module-class or module-function
*~ template files
*/
declare global {
/*~ Here, declare things that go in the global namespace, or augment
*~ existing declarations in the global namespace
*/
interface String {
fancyFormat(opts: StringFormatOptions): string;
}
}
Beware though:
This pattern is somewhat dangerous due to the possibility of runtime conflicts, but we can still write a declaration file for it.
It's better to have a SharedModules for everting that you want to use in the entire application more than one place according to the Angular official document. In this SharedModules you can have different directory app structure for all common things such as Models, Services, Interceptors, Pipe, components and etc.
Then Use this module on your main app.module.ts and import what you need.
For more information study this helpful & quick guide on PluralSight.
I'm using Webpack v4, and I have jQuery plugins which I currently load into our app with the webpack-merge-and-include-globally webpack plugin (and then manually load these into the html file with a <script> tag) but I would like to be able to move this into our main app code, so that webpack can be aware of them. There's been issues where some dependancies/classes are loaded twice, once in the merge-plugin mentioned above, and again in the Webpack dynamic imports.
So far its been hit and miss trying to get jQuery plugins to load and properly attached to the jQuery object.
Is there a recommended way to import jQuery plugins, as its not like a normal JavaScript ES6 class which you can just prefix with export class ClassName or export default class ClassName, because the plugin is wrapped in an IIFE (Immediately Invoked Function Expression).
A few potential solutions:
Option 1 - jQuery plugin that does not need its own global
import 'myapp/jquery-plugins/MyjQueryPlugin';
This one seemed potentially too good to be true / too easy, as it did not require new loaders.
Add the import statement without a name, just the script path. This should self execute the script, similar to how it would on a load from HTML.
Note that this would not work with a script that needs to be Global. For that, use the expose-loader in option 2 to specify what globals to expose.
As I found that each plugin/library/class I had to work with required a different way of handling it, I will also mention some other methods I found useful, and may be useful to others:
Option 2 - globals, such as jQuery
import 'expose-loader?exposes[]=$&exposes[]=jQuery!jquery';
This would import and execute it as it went, so that the next import line could use the global variable straight away.
Option 3 - alternative for globals
import MyClass from './views/MyClass';
window.MyClass = MyClass;
You can import, and then set on the window yourself, but if you have several import statements, and the latter depend on the first one already being available, then this wont work, as its not yet defined. See option 2. This is my least favorite, but worth mentioning as a fallback.
Option 4
Use the [webpack-merge-and-include-globally][1] plugin, but this is the one I was trying to avoid/reduce the use of, as its outside of "webpack's awareness."
Others
There's also other loaders like raw-loader, which you can use as normal with a !! in the import, or with a .then promise to control execution after load.
import('raw-loader!someScript.js').then(rawModule => eval.call(null, rawModule.default))
This is the example given by the docs in script-loader as an alternative, as script-loader is deprecated.
I've been looking to develop a method for loading modules and/or components into an AOT-compiled Angular 4 application and been stymied by a variety of solutions that never quite seem to get me where I want to be.
My requirements are as such:
My main application is AOT compiled, and has no knowledge of what it is loading until runtime, so I cannot specifically identify my dynamic module as an entry component at compile time (which is explicitly necessary for the 'dynamic' component loading example presented on Angular.io)
I'd ideally love to be able to pull the code from a back end database via a GET request, but I can survive it simply living in a folder alongside the compiled site.
I'm using Webpack to compile my main application, breaking it into chunks - and so a lot of the SystemJS based solutions seem like dead ends - based on my current research, I could be wrong about this.
I don't need to know or have access to any components of my main application directly - in essence, I'd be loading one angular app into another, with the dynamically loaded module only perhaps having a few tightly controlled explicit interface points with the parent application.
I've explored using tools like SystemJsNgModuleLoader - which seems to require that I have the Angular compiler present, which I'm happy to do if AOT somehow allowed me to include it even if I'm not using it elsewhere. I've also looked into directly compiling my dynamic module using ngc and loading the resulting ngfactory and compiled component/module, but I'm not clear if this is at all possible or if so - what tools Angular makes available to do so. I have also seen references to ANALYZE_FOR_ENTRY_COMPONENTS - but can't clearly dig up what the limitations of this are, as first analysis indicates its not quite what I'm looking for either.
I had assumed I might be able to define a common interface and then simply make a get request to bring my dynamic component into my application - but Angular seems painfully allergic to anything I try to do short of stepping outside of it alltogether and trying to attach non-angular code to the DOM directly.
Is what I'm trying to do even possible? Does Angular 2+ simply despise this kind of on the fly modification of its internal application architecture?
I think I found an article that describes exactly what you are trying to do. In short you need to take over the bootstrap lifecycle.
The magic is in this snippet here.
import {AComponentNgFactory, BComponentNgFactory} from './components.ngfactory.ts';
#NgModule({
imports: [BrowserModule],
declarations: [AComponent, BComponent]
})
export class AppModule {
ngDoBootstrap(app) {
fetch('url/to/fetch/component/name')
.then((name)=>{ this.bootstrapRootComponent(app, name)});
}
bootstrapRootComponent(app, name) {
const options = {
'a-comp': AComponentNgFactory,
'b-comp': BComponentNgFactory
};
https://blog.angularindepth.com/how-to-manually-bootstrap-an-angular-application-9a36ccf86429
I have an AngularJS project with a shared directory, in which there are several shared components.
- shared
- index.js
- alert
- index.js
- alert.component.js
- alert.controller.js
- alert.tpl.html
- alert.scss
- logging
- index.js
- logging.component.js
- logging.controller.js
- logging.tpl.html
- logging.scss
The code is written in a modular way in ES6. So for instance alert.component.js might look like this:
import controller from './alert.controller'
export const Alert = {
controller,
templateUrl: 'shared/alert/alert.tpl.html'
};
I would like to have one AngularJS module called shared in which both components are defined. My question is on what level should I actually define the component. Should it be inside the component directory (shared/alert/index.js) or in the shared directory (shared/index.js).
In the first case, the file shared/alert/index.js, would look like this:
import { Alert } from './alert.component';
angular.module('shared').component('Alert', Alert);
And in the second case, the file would look like this:
export { Alert } from './alert.component';
And then both components would be defined in shared/index.js:
import { Alert } from './alert';
angular.module('shared').component('Alert', Alert);
import { Logging } from './logging';
angular.module('shared').component('Logging', Logging);
The first case seems a bit odd to me, since I kind of let the component add itself to the application. In the second case however I end up with a huge index.js file, if I have many shared components. So I was wondering what other up and down sides each of these approaches has and if there any best practices?
As with any 'best practice', the preferable way to do this is deduced from possible problems that can appear in this situation.
angular.module('shared') module getter is generally an antipattern, especially in modular environment. It should be evaluated after the module was defined with angular.module('shared', []) module setter. Doing the opposite will result in race condition and error.
In the first case importing shared/alert/index.js in tests or another module will result in error because shared module wasn't defined yet.
In the second case there will be no such problem, but only if shared module is defined in shared/index.js.
The approach that plays well with ES modules is one module per file. The result is highly modular application with relatively low amount of boilerplate code. The benefits are reusability and testability, submodules can depend on each other but aren't coupled to share.
This is important consideration if some of submodules contain items that affect the entire application - decorators, config/run blocks, third-party modules that contain them (router).
When I want to debug my requirejs app, I need to reference my application everytime with something like:
var App = require('app');
as stated here:
http://requirejs.org/docs/api.html#modulenotes
From that moment I can access everything via console because the App variable points to my application instance.. However, it is very annoying to have to do it after every page refresh. Is there any alternative that would help improve the development workflow?
You could deliberately export a reference to your application into the global space. This is actually what I do. I select a name that has very little likelihood of clashing. In your app module you could do this after your App object is created: window._myproject_app = App. This is then accessible as the global _myproject_app. You can start writing the first characters and use autocomplete rather than type the whole thing when you want to access it.
If you want the export to occur only in testing you can use RequireJS' config facility to pass configuration that tells the module responsible to export the instance whether it should export it or not.