1

I'm a back end dev working on a project which includes an ember front end. Our project is unusual in that we have no production access; we write the code and deliver to client. The client is only comfortable/willing to use the Microsoft web stack, so we build the ember project, wrap the resulting contents into a simple Visual Studio project, and hand it over for deployment.

This client has unfortunately put us in a position that is apparently unusual in the ember world:

  • Client is unwilling to install or execute any of the ember-cli tools or commands
  • Client uses different directory structures for test and production sites (i.e. "http://staging.example.com/project" vs. "http://project.example.com/")
  • To honor the above requirements, we have been shipping separate builds for the two different environments. But this is also considered unacceptable in the long term.

Obviously, this is a situation that no one would have chosen with perfect foresight. Most of these restrictions were not made explicit until it was too late, but realistically the client will not be changing them. I am looking for a technical solution that looks like this:

  1. We develop in ember
  2. We use ember-cli tools (or equivalent) to build front-end
  3. We package results into one visual studio project, which may include web.config for client's test environments
  4. Zip up and deliver to client
  5. Based on settings in web.config, our ember project configures itself to:
    • set baseURL to appropriate value
    • connect to our REST API located at environment-specific URL

In order to solve the problem, I have been reviewing the following:

Unfortunately, I am personally unfamiliar with ember. So I don't understand how baseURL is really used yet, and why it seems to be so awkward to parameterize ember at deploy- or runtime. Where can I go to learn how to mash our work into an acceptable deployment process?

Is it possible to send values for baseURL or ourBackendApiURL to ember by putting META tags onto the index.html that loads the site?

Community
  • 1
  • 1
phil
  • 33
  • 2

4 Answers4

0

You can get rid of baseURL by setting baseURL: null in your environment.js. This will prevent ember-cli from generating a base tag. Also, if you are using location hash for urls (http://example.com/index.html#/path-to-route), I suggest to set locationType: 'hash' in environment.js. With default settings you will have problems if ember app located not in web-server's root directory.

Gennady Dogaev
  • 5,433
  • 1
  • 11
  • 21
0

Then when it was explained that the un-communicated requirements are really obstructive and will require additional man-hours, they of course understand you need to bill that out? ;)

You can try just adding this:

<base href="project">

It should be automatically picked up. Otherwise in app.js you can override the baseURL and rootURL property:

var Router = Ember.Router.extend({
  location: 'history',
  rootURL: function(){
    return "/random/";
  }.property(),
  baseURL: function(){
    return "/more-random/";
  }.property()
});
Kit Sunde
  • 32,665
  • 22
  • 111
  • 176
  • Thanks Kit! When I googled the base tag (I'd never seen it) I found this: https://github.com/ember-cli/ember-cli/issues/2633 and also http://stackoverflow.com/questions/1889076/is-it-recommended-to-use-the-base-html-tag which make me a big nervous. But it's pretty close to the solution I had in mind. I'll have to talk to my teammate who is building the ember portion of the project. – phil Aug 14 '15 at 19:47
  • @phil Wow such a dramatization in that thread. I'm fairly well aware of how the `` tag works it's literally for this case. Figure out if you have things in your particular case that prevents you from using it, it's just a tool. :) – Kit Sunde Aug 14 '15 at 19:56
  • I don't think we will, we're not using SVG or anything unusual. So I think in this case it will work as you suggest. Thanks again! – phil Aug 15 '15 at 01:53
0

I would consider going with something like ember-cli-dotenv so you can specify your baseURL at build/runtime. All they need to do is either specify BASE_URL=https://whatever-they-want.crazyclient.com in a .env file in the root of the project (ignored from version control), or to specify BASE_URL in the actual environment. This allows you and them to use the server you choose.

ember-cli implementation:

// Brocfile.js or ember-cli-build.js:
var app = new EmberApp({
  dotEnv: {
    clientAllowedKeys: ['ROOT_URL', 'BASE_URL']
  }
});

// pre-generated config from ember-cli
module.exports = app.toTree();

And then:

// config/environment.js
module.exports = function(environment){
  return {
    ROOT_URL: process.env.ROOT_URL,
    BASE_URL: process.env.BASE_URL,
  }
};

Finally:

var Router = Ember.Router.extend({
  location: 'history',
  rootURL: function(){
    return ENV['ROOT_URL'] || 'somedefault';
  }.property(),
  baseURL: function(){
    return ENV['BASE_URL'] || 'someotherdefault';
  }.property()
});
mpowered
  • 11,779
  • 2
  • 11
  • 18
0

Here's what ultimately solved it. Basically, we took the index.html which was created by "ember build", and found the meta tag which was passing in the values from environment.js to our javascript at runtime. By generating that meta tag in index.cshtml, we were able to use values specified in web.config.

Now when we build the app to hand off, we simply ignore the index.html that it generates, but add the rest of the assets to a pre-made visual studio web project. That project may be configured for testing or production.

First, I created an empty web application in visual studio. In web.config, I added this:

<appSettings>
  <add key="hostName" value="https://apps.example.com/" />
  <add key="baseURL" value="/projectDir/" />
  <add key="serverNamespace" value="api" />
  <add key="imgSrc" value="https://images.example.com" />
</appSettings>    

and then index.cshtml was written to make use of those values:

@{
    if (!Request.Url.AbsoluteUri.EndsWith("/"))
    {
        Response.Redirect(Request.Url.AbsoluteUri + "/");
    }    

    var configStr = @"{{
    ""modulePrefix"": ""foo-bar"",
    ""podModulePrefix"": ""foo-bar/pods"",
    ""environment"": ""production"",
    ""baseURL"": ""{3}"",
    ""locationType"": ""hash"",
    ""namespace"": ""{0}"",
    ""host"": ""{1}"",
    ""foo-auth-host"": ""{1}"",
    ""APP"": {{
        ""name"": ""foo-bar"",
        ""version"": ""0.0.0""
    }},
    ""contentSecurityPolicy"": {{
        ""default-src"": ""'none'"",
        ""script-src"": ""'self'"",
        ""font-src"": ""'self'"",
        ""img-src"": ""'self' {2}"",
        ""style-src"": ""'self'"",
        ""media-src"": ""'self'"",
        ""connect-src"": ""'self' {1}""
    }},
    ""simple-auth"": {{
        ""authorizer"": ""authorizer:foo"",
        ""routeAfterAuthentication"": ""/"",
        ""store"": ""simple-auth-session-store:local-storage""
    }},
    ""contentSecurityPolicyHeader"": ""Content-Security-Policy-Report-Only"",
    ""exportApplicationGlobal"": false
}}";
    var serverNamespace = System.Web.Configuration.WebConfigurationManager.AppSettings["serverNamespace"];
    var hostName = System.Web.Configuration.WebConfigurationManager.AppSettings["hostName"];
    var imgSrc = System.Web.Configuration.WebConfigurationManager.AppSettings["imgSrc"];
    var baseUrl = System.Web.Configuration.WebConfigurationManager.AppSettings["baseURL"];

    var configStrPopulated = string.Format(configStr, serverNamespace, hostName, imgSrc, baseUrl);
    var configStrCompacted = System.Text.RegularExpressions.Regex.Replace(configStrPopulated, @"\s+", "");
    var configStrEncoded = HttpUtility.UrlEncode(configStrCompacted);
}<!DOCTYPE html>
<html>
<head>
    ... 
    <meta name="foo-bar/config/environment" content="@configStrEncoded" />
    ... 
</head>
<body>
    <script src="assets/vendor.js"></script>
    <script src="assets/foo-bar.js"></script>
</body>
</html>
phil
  • 33
  • 2