Search code examples
javascriptamdsystemjsjs-amd

SystemJS Builder - window not defined


I am trying to build my project as a Self-Executing Bundle (SFX) with Gulp and SystemJS-Builder. When I run my gulp task, I keep getting the error, "window is not defined." I researched the issue and could not find a solution.

Here is my gulp build file

var gulp = require('gulp');
var path = require('path');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var Builder = require('systemjs-builder');

gulp.task('bundle:js', function () {
    var builder = new Builder('MyApplication/application/source', 'MyApplication/application/source/config.js');

    return builder.buildStatic('MyApplication/application/source/app.js', 'MyApplication/application/js/Site.min.js', {
        format: "amd"
    });
});

Here is my SystemJS configuration:

(function () {

    window.define = System.amdDefine;
    window.require = window.requirejs = System.amdRequire;

    var kendoVersion = "2016.3.914";

    var map = {
        text: "../Scripts/text.js",
        app: "app.js",
        main: "main.js",
        aes: "../../../Scripts/aes.js",
        jquery: "../../../Scripts/kendo/" + kendoVersion + "/jquery.min.js",
        kendo: "vendor/kendo/kendo.js",
        DataTables: "../../../Scripts/DataTables/datatables.js",
        k: "../../../Scripts/kendo/" + kendoVersion + "/",
        bootstrap: "../../../Scripts/bootstrap.js",
        lodash: "../../../Scripts/lodash.js",
        moment: "../../../Scripts/moment.js",
        ajaxSetup: "security/ajaxSetup.js",
        q: "../../../Scripts/q.js",
        toastr: "../../../Scripts/toastr.js",
        wizards: "viewmodels/shared",
        'kendo.core.min': "../../../Scripts/kendo/" + kendoVersion + "/kendo.core.min.js"
    };

    var paths = {
        'kendo.*': "../../../Scripts/kendo/" + kendoVersion + "/kendo.*.js",
        jquery: "../../../Scripts/kendo/" + kendoVersion + "/jquery.min.js",
        bootstrap: "../../../Scripts/bootstrap.js"
    };

    var meta = {
        app: { deps: ["kendo", "jquery"] },
        main: { deps: ["jquery"] },
        jquery: { exports: ["jQuery", "$"], format: "global" },
        kendo: { deps: ["jquery"] },
        bootstrap: { deps: ["jquery"] },
        'kendo.core.min': { deps: ["jquery"] },
        DataTables: { deps: ["jquery"], exports: "$.fn.DataTable" },
        toastr: { deps: ["jquery"] }
    };

    var packages = {
        pages: {
            main: 'views/*.html',
            format: 'amd',
            defaultExtension: 'html'
        }
    };

    var config = {
        baseURL: "application/source",
        defaultJSExtensions: true,
        packages: packages,
        map: map,
        paths: paths,
        meta: meta
    };

    System.config(config);
    System.import("main");

})(this);

I load SystemJS in my index page. Here is my Index.cshtml page

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>My Application</title>
    <meta name="description" content=""/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
    @Styles.Render("~/application/css/site.min.css")
    <script src="@Url.Content("~/Scripts/modernizr-2.8.3.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/localStoragePolyFill.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/system.js")" type="text/javascript"></script>
</head>
<body>

    @Html.AntiForgeryToken()
    <div id="applicationHost" class="page-wrap">

        <!-- The application is rendered here -->

    </div>

    <script src="@Url.Content("~/application/source/config.js")" type="text/javascript"></script>

</body>
</html>

I believe the issue is this line of code in the config

window.define = System.amdDefine;
window.require = window.requirejs = System.amdRequire;

Where does the above line of code go if not in the config?


Solution

  • I have fixed the issue by splitting out the configuration and startup. I previously had the configuration and startup in the same file. My configuration file has configuration only, I have a separate startup file that actually starts the application.

    Index.cshtml

    @using System.Web.Optimization;
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>My Application</title>
        <meta name="description" content=""/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
        @Styles.Render("~/application/css/site.min.css")
        <script src="@Url.Content("~/Scripts/modernizr-2.8.3.js")" type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/localStoragePolyFill.js")" type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/system.js")" type="text/javascript"></script>
    </head>
    <body>
    
        @Html.AntiForgeryToken()
        <div id="applicationHost" class="page-wrap">
    
            <!-- The application is rendered here -->
    
        </div>
    
        <script src="@Url.Content("~/application/source/startup.js")" type="text/javascript"></script>
    
    </body>
    </html>
    

    Startup.js

    // make sure we can load AMD files
    window.define = System.amdDefine;
    window.require = window.requirejs = System.amdRequire;
    
    // fire startup
    window.require(["application/source/config.js"], function () {
    
        // start app once config is done loading
        System.import("main");
    
    });
    

    config.js

    System.config({
    
        baseURL: "application/source",
        defaultJSExtensions: true,
        packages:{
            pages: {
                    main: 'views/*.html',
                    format: 'amd',
                    defaultExtension: 'html'
            }
        },
        map: {
            text: "../Scripts/text.js",
            app: "app.js",
            main: "main.js",
            aes: "../../../Scripts/aes.js",
            jquery: "../../../Scripts/kendo/2016.3.914/jquery.min.js",
            kendo: "vendor/kendo/kendo.js",
            DataTables: "../../../Scripts/DataTables/datatables.js",
            k: "../../../Scripts/kendo/2016.3.914/",
            bootstrap: "../../../Scripts/bootstrap.js",
            lodash: "../../../Scripts/lodash.js",
            moment: "../../../Scripts/moment.js",
            ajaxSetup: "security/ajaxSetup.js",
            q: "../../../Scripts/q.js",
            toastr: "../../../Scripts/toastr.js",
            wizards: "viewmodels/shared",
            'kendo.core.min': "../../../Scripts/kendo/2016.3.914/kendo.core.min.js"
        },
        paths: {
            'kendo.*': "../../../Scripts/kendo/2016.3.914/kendo.*.js",
            jquery: "../../../Scripts/kendo/2016.3.914/jquery.min.js",
            bootstrap: "../../../Scripts/bootstrap.js"
        },
        meta: {
            app: { deps: ["kendo", "jquery"] },
            main: { deps: ["jquery"] },
            jquery: { exports: ["jQuery", "$"], format: "global" },
            kendo: { deps: ["jquery"] },
            bootstrap: { deps: ["jquery"] },
            'kendo.core.min': { deps: ["jquery"] },
            DataTables: { deps: ["jquery"], exports: "$.fn.DataTable" },
            toastr: { deps: ["jquery"] }
        }
    });
    

    I am not sure that this is the correct solution, but it did solve the "window not defined" issue.