1

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/angular2@2.0.0-beta.9/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 :(

roonie
  • 763
  • 1
  • 9
  • 15
  • Seems like you are missing a script tag. There are tons of questions with this error message. (I don't use TS myself and don't know details) – Günter Zöchbauer Apr 03 '16 at 07:55
  • I added an update on my answer to explain why removing `"angular2":"npm:angular2@2.0.0-beta.9"` worked. – Abdulrahman Alsoghayer Apr 03 '16 at 22:10
  • Thanks @Abdulrahman, your update made total sense. Seems like I should just take angular out of node_modules anyway since I won't be using it on the backend – roonie Apr 04 '16 at 00:04

2 Answers2

4

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:angular2@2.0.0-beta.9":

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/angular2@2.0.0-beta.9 it will be served from jspm_packages. So, when you have the lines:

paths: {
  ...
  "npm:*": "jspm_packages/npm/*"
},
map:{
  `"angular2": "npm:angular2@2.0.0-beta.9"`
}

every request to angular2 will be translated to: jspm_packages/npm/angular2@2.0.0-beta.9. But It should've been just /npm/angular2@2.0.0-beta.9.

It worked when you remove "angular2": "npm:angular2@2.0.0-beta.9" 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/angular2@2.0.0-beta.9/bundles/angular2-polyfills.min.js"></script>
<script src="jspm_packages/system.js"></script>
Abdulrahman Alsoghayer
  • 16,462
  • 7
  • 51
  • 56
  • Hm, that got rid of the error message, but it still has the transclusion message "Loading" instead of the template string that I put in the App Component that gets bootstrapped (just a "hello world"). Any console logs in bootstrap.ts and app.component.ts don't get logged, and when i inspect the System object in the console, it seems like this package/module is also undefined. – roonie Apr 03 '16 at 16:48
  • @roonie I updated my answer. please try it. If it doesn't work, please update your answer with the contents of your `index.html`. Also the folder structure if possible. – Abdulrahman Alsoghayer Apr 03 '16 at 16:59
  • The folder structure is like this, and i also put in the server code where I'm serving up content: https://jsfiddle.net/cejk0jw3/ – roonie Apr 03 '16 at 17:11
  • @roonie I updated my answer again. Hopefully, it will work this time :) – Abdulrahman Alsoghayer Apr 03 '16 at 18:03
  • Ah that sort of worked. It now recognizes `bootstrap.js`, but it says `require is not a function` – roonie Apr 03 '16 at 18:17
  • This is what the compiled js looks like: `(function(System, SystemJS, require) {"use strict"; var browser_1 = require('angular2/platform/browser'); var app_component_1 = require('./app.component'); console.log('bs', browser_1.bootstrap); browser_1.bootstrap(app_component_1.AppComponent); })(System, System);` – roonie Apr 03 '16 at 18:18
  • In your Typescript `compilerOptions` add `"module": "system"` – Abdulrahman Alsoghayer Apr 03 '16 at 18:28
  • Yeah, i realized that, so what I did was use `system` for client-side code and `commonjs` for transpiling server-side code. I now get another error (ughhh) : `Error: SyntaxError: Unexpected token < Evaluating http://localhost:3000/jspm_packages/npm/angular2@2.0.0-beta.9/platform/browser.js Error loading http://localhost:3000/app/bootstrap.js` Here is my `bootstrap.ts` and `gulpfile.js` file for context: https://jsfiddle.net/p6ktuyar/1/ – roonie Apr 03 '16 at 18:37
  • @roonie do you have `npm/angular2@2.0.0-beta.9` inside your `jspm_packages` ? – Abdulrahman Alsoghayer Apr 03 '16 at 18:43
  • yep, I do. I looked at the specific file: `npm/angular2@2.0.0-beta.9/platform/browser` and it says "format cjs" at the top. I read through some of the SystemJs Docs and they said this line at the top of the file lets SystemJs know how to import the file. Do you think this might have something to do with it? – roonie Apr 03 '16 at 18:48
  • @roonie No I don't think so. The problem is that the browser is looking for `..../angular2@2.0.0-beta.9/platform/browser.j‌​s` but not finding it. Could you check the network tab and check the request and response to that file? – Abdulrahman Alsoghayer Apr 03 '16 at 18:59
  • yeah, I added it as part of the update to the original post. Basically, it's responding with my index.html file – roonie Apr 03 '16 at 19:04
  • @roonie that most likely means the file is not there :( . try installing angular2 again just to make sure , `jspm install angular2@2.0.0-beta.9`, also try accessing the file directly from the browser. `http://localhost:3000/jspm_packages/npm..../platform/browser.j‌​s` – Abdulrahman Alsoghayer Apr 03 '16 at 19:09
  • yeah i did, it still gets the index.html file. When i go to it in the browser too, it gives me back `index.html`. I logged out in the console whenever `app.get(/*, (req, res)...)` was called and its called 3 times when you go to `index.html`, when it should only get called once. Do you think all my express.statics are getting bypassed? – roonie Apr 03 '16 at 19:17
  • although it can't be, because when i console.log `System`, it shows the correct value... – roonie Apr 03 '16 at 19:17
  • actually, i logged out the `req._originalParsedUrl` in the `app.get('*', (req, res)...)` and there are two requests that shouldnt be hitting `/*`: 1) '/jspm_packages/npm/angular2@2.0.0-beta.9/platform/browser.js' 2) '/jspm_packages/npm/angular2@2.0.0-beta.9/core.js' – roonie Apr 03 '16 at 19:26
  • @roonie let continue this discussion in [chat room](http://chat.stackoverflow.com/rooms/108106/angular2bootstrap) – Abdulrahman Alsoghayer Apr 03 '16 at 19:32
  • unfortunately, I can't - i only have 19 reputation ( i need 20 ). Do you have gchat? – roonie Apr 03 '16 at 19:36
  • @roonie it's ok, I don't know what gchat is to be honest :D. Any way i just wanted to send you the url of `.../browser.js` to make sure there are no hidden characters or something. Although that's very unlikely to happen. Can you delete the file `bootstrap` and rewrite it again? just in case – Abdulrahman Alsoghayer Apr 03 '16 at 19:43
  • doesnt work. VScode also underlines `import {bootstrap} from 'angular2/platform/browser' in red in my `bootstrap.ts` file :( – roonie Apr 03 '16 at 19:49
  • @roonie that made things a lot easier, in `index.html`, remove the first: ` "angular2": "npm:angular2@2.0.0-beta.9",` – Abdulrahman Alsoghayer Apr 03 '16 at 20:14
  • thanks, that worked. Kind of confused why that was causing an issue though? – roonie Apr 03 '16 at 20:19
  • @roonie glad to hear it. I guess the reason was because you mapped `"npm:angular2@2.0.0-beta.9"` twice in `System.config({..})` – Abdulrahman Alsoghayer Apr 03 '16 at 20:23
0

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:

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • thanks, I read through that I know eventually I'll want the boilerplate to bundle and uglify my js, but for now I just wanted to bootstrap the app. I tried eliminating the packages object and just passing in the path to `bootstrap.js` but that didn't work either. I tried the solution above (`System.import('dist')), and that eliminates the unexpected token < error, but it doesn't actually bootstrap the app and none of the console logs in those files run :( – roonie Apr 03 '16 at 17:03