roonie
roonie

Reputation: 803

Why won't my angular 2 application bootstrap?

I'm trying to build a boilerplate template to bootstrap angular 2 applications using express, angular 2, typescript, gulp, and systemjs. For some reason, my index.html file won't recognize my bootstrap.js file. All my jade and typescript is located in src. I'm using gulp to transpile typescript from src to dist, and serving my static assets from node_modules and jspm_packages in express. But when it finally comes time to invoke System.import, like so: System.import('app').catch(console.error.bind(console)), i get:

Error: SyntaxError: Unexpected token < Evaluating http://localhost:3000/app/bootstrap.js Error loading http://localhost:3000/app/bootstrap.js

The error seems to be caused in angular2-polyfills.min.js.

Here is my basic express backend to give you an idea of how my assets and files are served up (I'm suspicious that i'm having a temporary brainfart and my paths are off):

const app = express();
app.use('/jspm_packages', express.static('jspm_packages'));
app.use('/node_modules', express.static('node_modules'));

app.get('*', function(req, res) {
  const file = fs.readFileSync('src/index.jade').toString();
  const html = jade.render(file);
  return res.send(html);
});

app.listen(process.env.PORT || 3000);

My index.html file is located in dist, the directory that holds all transpiled javascript. Here is the packages property on my System.config:

packages: {
          "dist": {
            "main": "bootstrap",
            "format": "system",
            "defaultExtension": "js"
          }
        },

I was under the impression that dist identifies the folder relative to the BASE_URL (which in my case is just /), and the main property identifies the file name. So I thought that by calling System.import('app'), it will look inside the app folder inside dist and find the bootstrap.js file to bootstrap my angular2 app, but that doesn't seem to be the case. When i open my up chrome console, bootstrap.js doesnt show up in my sources, so I'm guessing theres a path error somewhere, but I've tried every variation and can't seem to get it to work.

Any help would be greatly appreciated, thanks.

Update:

Here is my index.html: https://jsfiddle.net/r02r3jk3/ Here is the folder structure and server-side code that serves up content: https://jsfiddle.net/cejk0jw3/

When I inspect the network Tab for the response to the request for the browser.js file in angular2/platform, I get the following:

The request URL is http://localhost:3000/jspm_packages/npm/[email protected]/platform/browser.js

The response has a content-type of Content-Type:text/html; charset=utf-8 but the response is my index.html file :(

Upvotes: 1

Views: 1689

Answers (2)

Abdulrahman Alsoghayer
Abdulrahman Alsoghayer

Reputation: 16540

instead of app in System.import('app') it should be dist like this: System.import('dist') and your packages definition should be:

packages: {
    "dist": {
      "main": "app/bootstrap",
      "format": "system",
      "defaultExtension": "js"
    }
}

Update

Since your index.html is in the same folder where app is dist. Then you don't need dist in your packages definition.

Your definition should be:

packages: {
    "app": {
      "main": "bootstrap",
      "format": "system",
      "defaultExtension": "js"
    }
}

And import like:

System.import('app')

Update

I tried to duplicate your setup, and here are the issues I found:

In your backend code:

You are not serving the files inside dist. The line is commented out. That way, any request to app/* will be forwarded to index.html because of your app.get('*', ...)

You can uncomment your original line:
app.use('/dist', express.static('dist'));
or
app.use('/app',express.static('dist/app'))

Depends on which one you do, the packages object will be different.

I will go with the latter, app.use('/app',express.static('dist/app')). It just makes more since to me to hide the dist from the requests.

Also, check SystemJS module formats

The packages definition will be:

  packages: {
    "app": {
      "main": "bootstrap",
      //"format": "system",  // this was causing the main issue 
      format:"register",
      "defaultExtension": "js"
    }
  },

And lastly:

System.import('app')

Update

The last problem was about the line "angular2": "npm:[email protected]":

It was caused by the below two lines in server/index.js:

app.use(express.static('jspm_packages'));
app.use(express.static('node_modules'));

The problem is that all contents inside jspm_packages and node_modules will be served directly from the server. So, if you try to access : http://localhost:3000/angular2 it will be served from node_modules.
If if you try to access : http://localhost:3000/npm/[email protected] it will be served from jspm_packages. So, when you have the lines:

paths: {
  ...
  "npm:*": "jspm_packages/npm/*"
},
map:{
  `"angular2": "npm:[email protected]"`
}

every request to angular2 will be translated to: jspm_packages/npm/[email protected]. But It should've been just /npm/[email protected].

It worked when you remove "angular2": "npm:[email protected]" because angular2 now will be served from inside node_modules.

So the solution is to change your server/index.js to:

app.use('jspm_packages',express.static('jspm_packages'));
app.use('node_modules',express.static('node_modules'));

Also, the script tag inside the index.html should be now:

<script src="jspm_packages/npm/[email protected]/bundles/angular2-polyfills.min.js"></script>
<script src="jspm_packages/system.js"></script>

Upvotes: 4

Thierry Templier
Thierry Templier

Reputation: 202156

In fact it depends how to transpile your TypeScript files when building your application:

  • If you get a JS file per TypeScript, an anonymous module is created in the corresponding file ("System.register([ 'import1' ], ..."). In this case, the module is identified by its name and its path.
  • If you get only one JS file for all TypeScript files (with the outFile option), module names are explicitly defined when using the System.register function ( ("System.register('module name', [ 'import1' ], ...").

In your case, it seems that you're in the first case, so you could try this:

System.import('path/to/boot');

Note that if your index.html file is located un the dist folder, you need a sub folder at this level for your JS compiled files. This sub folder needs to be configured into your SystemJS in a "packages" entry.

See this question for more details:

Upvotes: 0

Related Questions