简体   繁体   中英

How to use same Code base for multiple AngularJS projects

This question is about code re-usability in angularJS .

Background info : My current application (application1) is using angularjs + kendo UI at the client side, it is in production now.

We are going to develop 4 more applications by using the same technologies. Functionalities of the 4 upcoming applications are almost 70-80% similar to the application1.

At this point, my management doesn't want to create a single application ( which consists the functionalities of all 5 application under one roof).

Current approach/goal is:

1.create 5 separate applications, and server-side also there are 5 different applications

2.reuse the client side code as much as possible

My current plan:

  1. separate the common code and keep this code as part of the core module (app.js).

  2. code refactoring - move to 'feature based directory' structure as suggested in this link .

  3. create an angular module for each feature (approx 10 modules).

My doubt is - As I am going to use the same " common " code for all 5 applications (copy paste as of now),

How I can make this common code behave differently for different applications?

For example,

  1. if application1, service call to /app1/gettasks or if application2, service call to /app2/gettasks , in this case, how I can pass app1/app2/app3... at runtime? Is this configurable?

  2. In simple, how can i tell the applicationName to angular code? After that, I can check for applicationName like below... (pseudocode)

     if(applicationName == app1){ //do app1 specific things }else if (applicationName==app2) { //do app2 specific things } 

PS: At server side I am using Spring Boot .

Please post your ideas...

Update:

In my common code, there are services, directives and filters are there. for directives & filters - there is no application specific code

  1. But, in Services , How can I make application specific REST URLs ?

  2. While/after the user logged in, how the "common code" knows the current application name? whether it is application1 or 2 or 3?

One possible solution could be to -

  • Maintain one 'config' property file per client app
  • Use build tools like Grunt or Gulp to pre-process your html/js/css files according to these configuration values. Its basically a text-search-replace and conditional include.

Eg https://github.com/jsoverson/grunt-preprocess

You can create your controller as object and then extend the default controller per project to add specific behavior, and use services as well.

Like here : https://github.com/nuxeo/nuxeo-drive/blob/master/nuxeo-drive-client/nxdrive/data/ui5/js/ndrive-settings.js

Thanks to @FrailWords's answer.

I completed my proposal to use the same UI codebase for multiple angular applications.I am sharing my leanings here.

Some approaches are staying same as I mentioned in this question.

List of Strategies to be followed in this proposal:

1.  Switch to feature based directory structure. 
2.  Create an angular module for each feature.
3.  Separate common code from instance specific code.
4.  Merge duplicate code.
5.  Remove unused code and outdated libraries.
6.  Re-organize codebase.
7.  Make common code as configurable.
8.  Use same configurable common code for all 5 instances.
9.  Use inheritance or similar mechanisms for extended functionality.
10. Identify & Move functions (methods) from instance specific code to common code.
11. Follow naming conventions.
12. Manage future requirements.
13. Use build tools like gulp or grunt and testing frameworks like jasmine.
14. Application specific look & feel.

How to implement these Strategies:

We will see solutions/approaches for each strategy below.

1. Switch to feature based directory structure.

Current directory structure:

It is based on angular layers/types. That is we placed all controllers in one folder, all services in another folder etc. This is good small applications.

Example:

在此输入图像描述

Proposed directory structure:

/resources
--/ui_core                                                      ui-core or common code
-----/app
-------------------core_module.js                   inject all modules from /ui_core/modules into this 
-------------------config_module.js                declare constants and inject into core_module 
-----/shared_services                                   part of core_module 
-----/shared_directives                                part of core_module – place directive’s js+html here
-----/shared_filters                                       part of core_module 
-----/shared_views                    
-----/shared_interceptors                 
-----/shared_content
------------/images
------------/icons
------------/signatures
-----/modules
 ------------/common_feature1
-------------------common_feature1_module.js
-------------------common_feature1Controller.js
-------------------common_feature1Service.js
-------------------common_feature1Directive.js
-------------------common_feature1Filter.js                                  if any
-------------------common_feature1_view.html
-------------------common_feature1_test.js
-------------------common_feature1.css                                         if any
------------/common_feature2
-------------------common_feature2_module.js
-------------------common_feature2Controller.js
-------------------common_feature2Service.js
-------------------common_feature2Directive.js
-------------------common_feature2Filter.js
-------------------common_feature2_view.html
-------------------common_feature2_test.js
-------------------common_feature2.css
-----/vendor                                                                      downloaded vendor libraries
------------/js
-------------------/angular
-------------------/kendo
-------------------/jquery
------------/css
-------------------/kendo
-------------------/bootstrap
------------/images
-------------------/kendo
-------------------/bootstrap
--/ui_equity                                    application specific code – for example: equity
-----/app                 
-------------------equity_module.js  inject ui_core module/any module as required.
-----/shared_services                     part of equity_module 
-----/shared_directives                  part of equity_module  – place directive’s js+html here
-----/shared_filters                         part of equity_module 
-----/shared_views
-----/interceptors
-----/content
------------/images
------------/icons
------------/signatures
-----/modules
 ------------/feature1
-------------------feature1_module.js
-------------------feature1Controller.js
-------------------feature1Service.js
-------------------feature1Directive.js
-------------------feature1Filter.js
-------------------feature1_view.html
-------------------feature1_test.js
-------------------feature1.css
------------/feature2
-------------------feature2_module.js
-------------------feature2Controller.js
-------------------feature2Service.js
-------------------feature2Directive.js
-------------------feature2Filter.js
-------------------feature2_view.html
-------------------feature2_test.js
-------------------feature2.css
--/minified
-----/ui_core
-----/ui_equity 
/webapp
-----/WEB-INF
------------/jsp
-------------------index.jsp
-------------------jsincludes.jsp
-------------------cssincludes.jsp
-------------------imageviewer.jsp
-------------------unauthorized.jsp

2. Create an angular module for each feature.

To make our applications modular, create an angular module for each major feature/functionality of our application. We can inject these modules wherever needed.

Benefits:

  1. Easy to reuse modular applications.

  2. Improved readability: No need to inject individual components into other components, injecting module is enough.

3. Separate common code from instance specific code.

List of items which can be part of ui_core (common code)

a.  Most of the directives
b.  Filters
c.  Utilities , such as arrayUtilities.js, dateUtilities.js, stringUtilities.js
d.  Services
e.  KendoGridServices & relevant controllers.
To make   kendoGrid as part of common code, below changes are required.

For example,
-   Create model outside datasource - Currently schema “model” is hardcoded inside abccontroller.js , instead of this create “kendo model” outside abccontroller.js and pass/inject to abccontroller.js

-   Currently “columns” are hardcoded inside kendoabcgridservice.js. Instead of this, create “columns array” outside and inject it into kendoabcgridservice.js .

-   Similarly, move out any other instance specific code from kendo grid.

Below Strategies are self-explanatory, so we can move to the next one...

    4.  Merge duplicate code.
    5.  Remove unused code and outdated libraries.
    6.  Re-organize codebase.

7. Make common code as configurable.

a. Create a configuration module inside common code

( /resources/ui_core/app/ config_module.js).

b. Declare constants inside that module, for example APP_NAME = 'equity' and whatever required.

c. Modify the common code (ui_core), by using APP_NAME constant, so that same code block will behave differently for different applications.

For example,

Instead of $resource('/equity/tasks') use $resource('/APP_NAME/tasks')

Note: Above is for example purpose only (as of now), changes in Service call URLs to be finalized after Server/Java side re-factoring.

Example 2:

If (APP_NAME == ‘equity’){
             //do ‘equity’ specific things
} else if (APP_NAME == ‘commodities’){  
           //do ‘commodities’ specific things
} else {
……………..
}

8. Use same configurable common code for all 5 instances.

    As explained earlier

9. Use inheritance or similar mechanisms for extended functionality.

If we need additional functionality apart from whatever available , instead of copy & paste existing files and adding code to that file, we can use inheritance kind of mechanism in angular as below.

Using

angular.extend 
Or 
angular.copy

or similar approaches.

10. Identify & Move functions (methods) from instance specific code to common code.

As explained earlier

11. Follow naming conventions

For better maintainability & consistency, define and follow certain naming convention for files.

For example,

If the functionality name is 'user', then naming can be like below.

/modules
-----/user
----------user_controller.js
----------user_service.js
----------user_directive.js
----------user_view.html
----------user_test.js

Either follow user_controller.js or user_ctrl .js , but , never do both at the same time.

12. Manage future requirements

As we are living in the real world , changes and enhancements are part of life. Once we implemented above proposal , it will be very easy to modify/enhance the features without affecting other part of the application.

Anyway, before add any functionality to the existing code base, ask this very important question to yourself (developer of this application).

Where I am going to add this feature, In Common code or application specific code?

Enjoy and Have Fun :-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM