RequireJS: Is there a way to achieve multiple base URLs?

后端 未结 4 2104
北恋
北恋 2020-12-12 17:35

I want to use a separate domain as a JavaScript framework and it will create a base require config which I can augment from the app.

foo.example.com
    main         


        
相关标签:
4条回答
  • 2020-12-12 17:44

    Answered by James Burke on RequireJS Github Issue's page: Issue #447: Multiple Base URLs · jrburke/requirejs.

    Turns out to be quite simple if data-main is the only entry point to your scripts(comments for more info), I solved my particular problem with the following:

    My app's index.html:

    <script src="http://framework.jpillora.com/js/lib/require.js" 
      data-main="http://framework.jpillora.com/js/framework" > </script>
    

    has the requirejs entry point set to framework.js:

    var framework = ... //set using script elements src attribute
    
    require.config({
    
        baseUrl: 'js/',
    
        //Framework paths
        paths: {
          'framework': framework,
          'lib'      : framework + 'js/lib',
          'ext'      : framework + 'js/ext',
          'util'     : framework + 'js/util'
        },
    
        //Shortcuts
        map: {
          '*': {
            ...
          }
        },
    
        //Non-modularised libraries with deps
        shim: {
          ...
        }
    });
    
    require(['main']);
    

    So instead of normally doing index.html->main.js, we're adding an extra step index.html->framework.js->main.js, which gives the app code knowledge of paths to the framework code.

    For example, in the app http://prettyprint.jpillora.com/, once require has loaded framework.js, it will setup paths to lib/... which to http://framework.jpillora.com/ and set the baseUrl as ./js/ so once main is required, it will have the base url set to it's own domain and lib pointing to another domain.

    Which results in require(['lib/foo', 'view/bar']); resolving to:

    http://framework.jpillora.com/js/lib/foo.js and http://prettyprint.jpillora.com/js/view/bar.js

    As displayed here, the app is only a main.js everything else comes from the framework:

    chrome devtools loaded app

    So finally, whenever I load an app's main.js via with the above framework.js, I then have access to all of my commonly used libraries and utility classes. See app source.

    Also note, with the r.js optimiser and a nice local file structure, one can also optimise the app into a single js file pulling only what's required from framework.

    0 讨论(0)
  • 2020-12-12 18:00

    Have a look at how we have handled routing and the context in BoilerplateJS which is a reference architecture for large-scale product development. We have used the library crossroads.js to route modules and UI components. All there is to do is add the path/hash to the set of routes and it will be routed through the framework.

    As an example all the paths of the UI components are added to the URL controller object.

    As for accessing the framework configuration information throughout the application, configurations/settings can be attached to the global-context object which can be accessed inside the application.

    0 讨论(0)
  • 2020-12-12 18:03

    The problem

    I had a similar problem while trying to set up a testing environment. I had a file structure like this:

    myApp/
        src/
            js/
                app.js
                data.js
                lib/underscore.js
        test/
            karma.conf.js
            test-main.js
            matchers.js
            spec/
                data.js
    

    Here's where it gets tricky: my app scripts (app.js and data.js) assume a RequireJS configuration that resolves data to src/js/data.js, lib/underscore to src/js/lib/underscore.js etc, so I need that configuration in my test environment as well:

    test/test-main.js
    -----------------
    require.config({
      // Karma serves files under /base, which is the basePath from your config file
      baseUrl: '/base/src/js',
      // ...
    });
    

    Now I can write my tests:

    test/spec/data.js
    -----------------
    define(['data', '../../test/matchers'], function(dataModule) {
        describe('The data module', function() {
            it('should satisfy my custom matcher', function() {
                expect(dataModule).toSatisfyMyCustomMatcher();
            });
        });
    });
    

    With some custom matchers:

    test/matchers.js
    ----------------
    define([], function() {
        beforeEach(function() {
            this.addMatchers({
                toSatisfyMyCustomMatcher: function() {
                    return this.actual.isGood;
                },
            });
        });
    });
    

    However, that '../../test/matchers' part is horrendously ugly. The test specifications shouldn't be bothered with knowing file paths to other modules - that's RequireJS's job. Instead we want to use symbolic names.

    The solution

    The RequireJS paths config can also map directories.

    The path that is used for a module name should not include an extension, since the path mapping could be for a directory.

    So, the solution is a simple path config:

    test/test-main.js
    -----------------
    require.config({
      baseUrl: '/base/src/js',
      paths: {
          test: '../../test',
      },
      // ...
    });
    

    Now I can refer to the test directory as if it were a child of the baseUrl:

    test/spec/data.js
    -----------------
    define(['data', 'test/matchers'], function(dataModule) {
        // ...
    });
    

    Which in my case effectively comes out pretty much the same as if I could have multiple baseUrls.

    0 讨论(0)
  • 2020-12-12 18:07

    requirejs multiversion

    TRY this

    context: A name to give to a loading context. This allows require.js to load multiple versions of modules in a page, as long as each top-level require call specifies a unique context string. To use it correctly, see the Multiversion Support section.

    0 讨论(0)
提交回复
热议问题