質問

I started an application in AngularJS couple of weeks ago. All my configuration variable are stored in a constant like this:

/**
 * defines constants for application
 */
define(['angular'], function (ng) {
    'use strict';
    return ng.module('app.constants', [])
        .constant('CONFIG', {
            node_port: 3700,
            api_host: 'api.acme.local',
            node_host: 'acme.com',
            facebook_app_id: 'xxxxxxxxx'
        });
});

The problem I have is that I need to change this value each time I want to push my application in stage. I'm using rsync so I could ignore this file and modify it once on the stage server. It might not be the best solution but it would work.

Now recently I've added a nodejs server to my application using express and socket.io, which mean I now have to setup the client in my angularjs application and the server.js. Because I'm using requirejs I also need to update the path for socket.io.

requirejs:

paths: {
        'jquery': 'bower_components/jquery/dist/jquery.min',
        ...
        'socketio': 'http://acme.local:3700/socket.io/socket.io'
    },

and my server.js:

var express = require('express'),
    debug = true,
    http = require('http'),
    _ = require('underscore'),
    server = express(),
    port = 3700,
    api_host = 'api.acme.local',
    io = require('socket.io').listen(server.listen(port), {log: debug});

...

var options = {
    hostname: api_host,
    port: 80,
    path: '/courses',
    method: 'GET'
};

var req = http.request(options, function(res) {
    var output = '';

    res.setEncoding('utf8');
    res.on('data', function (chunk) {
        output += chunk;
    });
...

So basically I'm ending up with duplicated variable for my node application and angular application, plus I need to toggle values between dev and stage variables values.

What would be the best solution to this problem?

Thanks


UPDATE 1

Just found out that requirejs has a failover option for the path, so for now I'm using it:

paths: {
    'jquery': 'bower_components/jquery/dist/jquery.min',
    ...
    'socketio': [
        'http://stage.acme.com:3700/socket.io/socket.io',
        'http://acme.local:3700/socket.io/socket.io'
    ]
},

Still investigating how to do it properly

役に立ちましたか?

解決

I'm in the same configuration as you.

Basically, here is my architecture :

  • a "front" folder for angular
  • a "back" folder for anodejs
  • a "common" folder for shared files between angular and node

  • one specific configuration file by environment in the common folder (sharzed by angular and node)

  • one specific configuration file by i18n locale in the common folder (sharzed by angular and node)
  • a "constant-type" angular module filled in at runtime/buildtime by Grunt

and Grunt with a few modules installed. Then :

  • When running nodejs server on a specific environment, only the environment config file is loaded.
  • When packaging angularjs, this same file is used to create the constant-type" angular module which keys comes from the static JSON config file.
  • same thing for i18n contant module

That way both sides, angular and nodejs shares the same configuration and have synchronized configurations.

For an example of this behavior, see my detailed and Grunt-powered answer here : How to set AngularjJS base URL dynamically based on fetched environment variable? :


I personnaly do this kind of stuff with grunt.

When I run my angular-app I have multiple tasks :

> grunt run --target=dev
> grunt run --target=prod
> grunt build --target=dev
> grunt build --target=prod
> etc...

Then grunt do strings replacement with the help of the grunt-preprocess module :

my constants.tpl.js file gets parsed :

[...]
baseUrl:           '/* @echo ENV_WS_URL */',
[...]

and the url is populated.

There are endless possibilities (string replacements, file copy, etc).

Doing it with grunt ensure that dev config files do not go in production for example..

I can put more details if you're interested but I only wanted to show you a different approach.

edit gruntFile example :

'use strict';

module.exports = function(grunt) {

    /**
     * Retrieving current target
     */
    var target = grunt.option('target') || 'dev';
    var availableTargets = [
        'dev',
        'prod'
    ];

    /**
     * Load environment-specific variables
     */
    var envConfig = grunt.file.readJSON('conf.' + target + '.json');

    /**
     * This is the configuration object Grunt uses to give each plugin its
     * instructions.
     */
    grunt.initConfig({
        env: envConfig,       

        /*****************************************/
        /* Build files to a specific env or mode */
        /*****************************************/
        preprocess: {
            options: {
                context: {
                    ENV_WS_URL: '<%= env.wsUrl %>'
                }
            },
            constants: {
                src: 'constants.tpl.js',
                dest: 'constants.js'
            }
        },

        karma: {
            unit: {
                configFile: '<%= src.karma %>',
                autoWatch: false,
                singleRun: true
            },
            watch: {
                configFile: '<%= src.karma %>',
                autoWatch: true,
                singleRun: false
            }
        }

    });


    /****************/
    /* Plugins load */
    /****************/
    grunt.loadNpmTasks('grunt-preprocess');

    /*******************/
    /* Available tasks */
    /*******************/
    grunt.registerTask('run', 'Run task, launch web server for dev part', ['preprocess:constants']);

};

Now, the command :

> grunt run --target=dev

will create a new file "constants.js" with a environment-specific url which will be used by Angular

他のヒント

I've seen a better aprouch:

Suppose you have a client-side configuration as an Angular module like this:

angular.module('config', [])
    .constant('configuration', {
    API_END_POINT: 'localhost:3000',
    APP_END_POINT : "localhost:9000",
    "ORIGIN_HOST" : "localhost:3000",
    'ENVIRONMENT' : 'dev'
});

You’d like to pull these constants into your nodejs environment to keep constants canonical. You don’t want some super-complex module to make things messy.

Simply define a “fake angular” on the server-side, then grab your constants.

/* inside nodejs now */
var CONSTANTS;

angular = {
    module : function() {
        return {
            constant: function(name, constants) {
                CONSTANTS = constants;
            }
        }
    }
}

require("../web/scripts/config.js");
console.log(JSON.stringify(CONSTANTS)); // easy peasy

Thought that might help a few of you struggling with sharing code between Angular and node apps!

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top