Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Architecture: Combine several JavaScript projects (modular) [closed]

I would like to create a clean archtecture for my JavaScript project. The project consists of one Node.js server and two separate Angular.js front-ends with different purposes. For building the front-ends I use a custom grunt build each. The build results in one single HTML file per project and two minified/uglified CSS and JavaScript files. Each front-end is then running on a separate minimal version of a Node server (serves only the static files).

So far, so clear. The goal is now to make it possible to add plugin modules to each one of the three core projects. A module should extend the JavaScript of either one of the projects. This means e.g. in case of one front-end to add an additional angular module to the angular configuration. I already know where and how to add the angular module code into the core app.

The problem is now: How do you create a reasonable build process over multiple projects which is also depending on plugin modules? I came up with two solutions.

  1. I could add a plugin as an NPM dependency to one of the core projects. This has however the drawback, that every change in the module needs to be pushed to NPM and it is not very convenient to develop the plugin module like this. A plugin is not runnable on its own.
  2. I could have a list of plugins inside the Gruntfile of one of the core projects. This list would contain local file paths to the modules. In the build of the core module, the builds of the plugins will be executed. This would however include to watch changes of the built files of the plugins. It is an unclean solution.
  3. I could have another project which contains dependencies to the core project and all the plugins and builds it all together. The question of how to add the dependency remains (case 1 or 2)

How would you solve that problem?

like image 918
ssc-hrep3 Avatar asked May 28 '16 23:05

ssc-hrep3


3 Answers

IMHO, it's not that related to task manager work (aka gulp, grunt or even webpack, it doesn't really matter here). The community goes to a place where you own lots of (relatively) tiny node modules that do one thing and do it well, so it's pretty connected to your first suggestion.

A VCS repo could look like this structure:

my-repo/
  package-1/
    package.json
  package-2/
    package.json
  package-3/
    package.json
  ...

... then you work with npm link to make symlinks inside the modules themselves, that way you don't have to publish the modules for getting updates.

There's a pretty new package called lerna that does exactly this npm link thingy, automatically (it detects your dependencies graph in your "local" modules and make a link between them), all you need to do is follow their structure. In addition, it makes publish smartly, you can run commands in all packages and bunch of other related things.

Babel, React are great examples of this modules-separation-of-concern. Babel works with lerna to automate the linking between the packages, here are their reasons to have a monorepo.

like image 160
Roy Miloh Avatar answered Sep 28 '22 01:09

Roy Miloh


I usually do exactly what you have described under 1. But I use local dependencies that will be concatenated by my build chain.

npm install ~/project_root/sub_project --save-dev

this way you do not need to push it all the time. you simply delete the node_module/sub_project folder and run npm install again inside your build chain.

with browserify you can then add your dependencies to your angular project.

A plugin is not runnable on its own.

I usually develop my services or directives as regular JavaScript classes and wrap them with angular.

var Service = require("./path/to/service.js")
module.exports = [function() {
    return {
        restrict: 'AC',
        link: function($scope, $element) {
            var someService = new Service();
            $scope.$watch("whatever",function(value){
                service.doSomething();
            })
        }
    };
}];

This way you can run them and test them independently from angular. This also comes in advantage when working with WebWorkers. Since they can not really(fully) be used with angular 1.X.

like image 34
Richard Burkhardt Avatar answered Sep 27 '22 23:09

Richard Burkhardt


I had a similar problem a few months ago. Installing dynamic dependencies could be solved fairly easy since you are familiar with streaming building systems like Grunt or Gulp.

  1. You may allocate a property inside your package.json like dependencies or devdependencies which will hold all additional info you need, bower.json or even a custom JSON file will do the trick too. I prefer NPM packaging manifests or Bower manifests as they provide a valid entry point for each module.
  2. Using grunt-auto-install you can dynamically install any additional module dependencies for your building process, the ones that you can parse from your project's main package.json file.
  3. Using each module's main property from each additional package.json will give you a file list to initialize an uglify or concatenating task .
like image 27
vorillaz Avatar answered Sep 28 '22 01:09

vorillaz