How to use multiple main.js files for RequireJs in

2019-04-29 18:56发布

问题:

I'm building a single-page app using, AngularJs + RequireJs in Play Framework 2.1.1. I have two application sitting inside the same Play server, admin dashboard and normal website. That's why I have two main.js files for Admin Dashboard and Normal website. The application structure looks like this. I got this from public/javascripts

We want to separate the two pages that's why we have two main.js files. However, the problem I'm facing right now is that in the root main.js everything is fine. If I go to my application http://localhost:9000/ everything is ok and if I look at the network panel on Firebug I only see require.js and main.js which is what I expected. However, when I go to admin dashboard http://localhost:9000/admin Every file is minified correctly. But when I look at the network I see all the javascript files which it should haven't been that. I thought each script should be loaded dynamically from requireJs. So, it means browser makes multiple calls to get all the necessary files instead of just get require.js and main.js to resolve dependencies. Am I doing anything wrong?

I got the structure from this project https://github.com/maxdow/angularjs-requirejs-seed

├── admin
│   ├── app.js
│   ├── bootstrap.js
│   ├── controllers
│   │   ├── AdminAppController.js
│   │   └── index.js
│   ├── directives
│   │   ├── Directive.js
│   │   └── index.js
│   ├── filters
│   │   └── index.js
│   ├── impl.js
│   ├── main.js
│   └── routes.js
├── app.js
├── bootstrap.js
├── controllers
│   ├── Controller.js
│   └── index.js
├── directives
│   ├── Directive.js
│   └── index.js
├── filters
│   └── index.js
├── impl.js
├── lib
│   └── angular
│       ├── angular-cookies.min.js
│       ├── angular-flash.min.js
│       ├── angular-resource.min.js
│       └── angular.min.js
├── main.js
├── routes.js
└── services
    ├── Service.js
    └── index.js

You will notice that inside admin/ there is main.js and also in the root I have another main.js

The code looks pretty much the same like this.

require.config({

    paths: {
        'angular': './lib/angular/angular.min',
        'angular-resource': './lib/angular/angular-resource.min',
        'angular-cookies': './lib/angular/angular-cookies.min'
    },

    /**
     * for libs that either do not support AMD out of the box, or
     * require some fine tuning to dependency mgt'
     */
    shim: {
        'angular': {
            exports: 'angular',
            deps: []
        },
        'angular-resource': {
            deps: ['angular']
        },
        'angular-cookies': {
            deps: ['angular']
        }
    }
});

require(['./bootstrap'], function () {
    //nothing to do here...see bootstrap.js
});

This is what my template looks like for the normal site

@helper.requireJs(core = routes.Assets.at("javascripts/require.js").url, module = routes.Assets.at("javascripts/main").url)

This is what my template for admin page looks like

@helper.requireJs(core = routes.Assets.at("javascripts/require.js").url,
                            module = routes.Assets.at("javascripts/admin/main").url)

And this is my Build.scala

  val main = play.Project(appName, appVersion, appDependencies).settings(
    requireJs += "main.js",
    requireJsShim += "main.js"

  )

This is what my build looks like when I do play start

[info] Loading project definition from /Users/myuser/MyProject/project/main/project
[info] Set current project to project (in build file:/Users/myuser/MyProject/project/main/)
[info] RequireJS optimization has begun...
[info] app.build.js:
[info] ({appDir: "javascripts",
[info]           baseUrl: ".",
[info]           dir:"javascripts-min", mainConfigFile: "javascripts/main.js", modules: [{name: "main"}]})

Tracing dependencies for: main
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/app.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/bootstrap.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/controllers/AdminAppController.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/controllers/index.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/directives/Directive.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/directives/index.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/filters/index.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/impl.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/main.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/admin/routes.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/app.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/bootstrap.js
min/controllers/Controller.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/directives/index.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/directives/Directive.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/filters/index.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/impl.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/lib/angular/angular-cookies.min.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/lib/angular/angular-flash.min.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/lib/angular/angular-resource.min.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/lib/angular/angular.min.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/main.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/routes.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/services/Service.js
Uglifying file: /Users/myuser/MyProject/project/main/target/scala-2.10/classes/public/javascripts-min/services/index.js

main.js
----------------
lib/angular/angular.min.js
filters/index.js
lib/angular/angular-resource.min.js
lib/angular/angular-cookies.min.js
services/index.js
directives/index.js
controllers/index.js
app.js
routes.js
controllers/Controller.js
directives/Directive.js
services/Service.js
impl.js
bootstrap.js
main.js

I have made some changes in Build.scala to be

requireJsShim += "main.js",
    requireJsShim += "admin/main.js",
    requireJs += "main.js",
    requireJs += "admin/main.js",

and I get this error instead

({appDir: "javascripts",
[info]           baseUrl: ".",
[info]           dir:"javascripts-min", mainConfigFile: "javascripts/main.jsadmin/main.js", modules: [{name: "main"},{name: "admin/main"}]})
Error: /Users/user/MyProject/project/main/target/scala-2.10/classes/public/javascripts/main.jsadmin/main.js does not exist.

You can see that it concatenates the two string together in requireJsShim and I need that for bootstrap to work for angularjs.

回答1:

In you build.scala file, add all your dynamic js files to requireJS, like for example :

val main = play.Project(appName, appVersion, appDependencies).settings(

    requireJsShim += "main-normal.js"
    requireJs += "main-normal.js",
    requireJs += "main-admin.js",

 )

Then when you start play using 'play start' , requireJS will treat these individual files as modules, which you can see in the console output as :

{
  appDir: "javascripts",
  baseUrl: ".",
  dir:"javascripts-min",
  mainConfigFile: "main-normal.js",
  modules: [
             {name: "main-normal"},
             {name: "main-admin"}
           ]
}

It will then start resolving dependencies for those js files, and in your site, inspect using firebug/chrome dev tools and in the network tab, it will reflect the changes, do a fresh reload/delete the cache in your browser to see the changes.

Also, for performance improvements, i suggest that you use the r.js file instead of default rhino compiler as suggested in the play framework docs, you can download it here : https://raw.github.com/jrburke/r.js/master/dist/r.js

copy the file into your project folder and add the following line to your build.scala above the requireJsShim line :

    requireNativePath := Some("r.js")

so, in effect your build.scala file should be :

val main = play.Project(appName, appVersion, appDependencies).settings(

    requireNativePath := Some("r.js"),
    requireJsShim += "main-normal.js"
    requireJs += "main-normal.js",
    requireJs += "main-admin.js",

 )