Skip to content

Module Development with the Angular template

The whole template is basically just a regular Angular base application with Webpack Module Federation and an injectable service that is wrapper for HortiView's Module API. ng serve behaves as it normally does - runs the application that can be openend in a browser, but ng build doesn't behave like in a basic Angular application. The default Angular configuration in angular.json for building was renamed to build_standalone, and build now serves the purpose of building a federated module that cannot run on its own, but is meant to be run in a Webpack Module Federation host app (HortiView in this case).

Local development

All you have to do to develop locally is to install npm packages and run ng serve. To make the local development easier, it's recommended to run the project in a browser with CORS policies turned off. Nothing else is required to run the project locally.

ng serve vs ng build

Running ng serve runs the Angular application in a regular way, just as any Angular application would be run. However, ng build has been modified (in angular.json) so that it wraps the whole application into Webpack Module Federation. This is required to run the module in HortiView.

Setup for deployment

A good approach would be to first register a module in HortiView before setting up the following.

The template is almost good to go, but you have to change a couple of things first in webpack.config.js

module.exports = {
    output: {
        uniqueName: "yourScopeName", // 1
        ///...
    },
    ///...
    plugins: [
        new ModuleFederationPlugin({
            name: "yourScopeName", // 1
            filename: "remoteEntry.js", // 3

            library: {type: 'window', name: 'yourScopeName'}, // 1

            exposes: {
                './YourComponentName': './src/loadApp.ts', // 2
            },

            ///...
        }),

        ///...
    ],
};

alt text

1) Change module.exports.output.uniqueName, module.exports.plugins.ModuleFederationPlugin.name and module.exports.plugins.ModuleFederationPlugin.library.name to what you have provided during the module registration in HortiView in the Remote Module Name (Scope) field, 2) Change module.exports.plugins.ModuleFederationPlugin.exposes property name to what you have provided during the module registration in HortiView in the Expose Component Name field, 3) You can change the name of the entry file which you will later on have to choose in the vendor page, but it can stay as it is.

Environments & building for deployment

There are currently 3 supported environments:

  • tes (test)
  • dem (demo)
  • prod (prod)

You can find environment files for each of them in src/environments. For local development you have to create the environment.local.ts. I recommend copy-pasting the environment file for tes and adding there the moduleId (from tes environment) and HortiView credentials.

export const environment = {
    COMMONDATA_API: 'https://app-hv-c-commondata-tes-weu-001.azurewebsites.net',
    MODULE_API: 'https://app-hv-c-moduleapi-tes-weu-001.azurewebsites.net',
    moduleId: '00000000-your-modu-leee-guid00000000', // your moduleId from the tes environment
    hvCreds: {
        username: 'john.doe@company.com', // your farmer account email
        password: 'abc!@#', // your farmer account password
        organizationId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', // the id of the organization you want to have active during the runtime
    }
}

In package.json you can find a build script for each environment:

  • build:tes
  • build:dem
  • build:prod

Routing

Routing is set up in src/app/app.routes.ts using the standard Angular router library.

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'first', component: FirstComponent },
  { path: 'second', component: SecondComponent },
];

Because of the HortiView overhead the way that routing works is that during the mounting of the module, there is a base HTML Element created with the href attribute set to the current website URL. The base URL when you open a module will be something like this:

https://app.hortiview.com/farm/modules/00000000-your-modu-leee-guid00000000/

that part won't interest you. The routing set up above takes into consideration only stuff put after that URL, so e.g.

https://app.hortiview.com/farm/modules/00000000-your-modu-leee-guid00000000/second

will move to the SecondComponent.

Other than that, the routing is done in the regular Angular name.

Module API - HortiViewDataService

At src/app/hortiview-data.service.ts there is the HortiViewDataService service which wraps the logic required to get data from the Module API. You can use the getEntity method to get data from the API by just putting the data area key as a parameter. Currently supported are:

  • fields
  • zones
  • farm_members
  • farm_organizations
  • farms

but it will work for all the keys that you can get from https://app-hv-c-commondata-{{env}}-weu-001.azurewebsites.net/api/v1/dataAreaEntity/dropdown, there are just no models for that in the template.

There are also methods that will return Module API data after modifying it a bit e.g. getFarms or getFieldsAndBlocks. You don't have to use them or you can write your own methods, up to you.

The service has a simple caching mechanism, so if you e.g. run getFarms method multiple times, you will get the same results from the cache.

Read More

For more on that topic please refer to this part of the React module template documentation ( the useEntity hook is just a wrapper for Module API calls) and more importantly the API section of the docs