angular / angular-cli

CLI tool for Angular
https://cli.angular.io
MIT License
26.74k stars 11.98k forks source link

angular universal server.ts fails #10787

Closed epgeroy closed 5 years ago

epgeroy commented 6 years ago

Versions

    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/

Angular CLI: 6.0.0
Node: 8.10.0
OS: linux x64
Angular: 5.2.9
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.6.0
@angular-devkit/build-angular     0.6.0
@angular-devkit/build-optimizer   0.6.0
@angular-devkit/core              0.0.29
@angular-devkit/schematics        0.6.0
@angular/cli                      6.0.0
@angular/platform-server          6.0.0
@ngtools/webpack                  6.0.0
@schematics/angular               0.6.0
@schematics/update                0.6.0
rxjs                              5.5.7
typescript                        2.4.2
webpack                           4.6.0
-----------------------------------------------------------------------------
Distributor ID: Debian
Description:    Debian GNU/Linux 9.4 (stretch)
Release:    9.4
Codename:   stretch

Repro steps

Observed behavior

project builds and the server runs, but when entering to localhost:4000 an error is throw

Node server listening on http://localhost:4000
ERROR { TypeError: StaticInjectorError[function (){} -> InjectionToken DocumentToken]:
  StaticInjectorError(Platform: core)[function (){} -> InjectionToken DocumentToken]:
    Right-hand side of 'instanceof' is not an object
    at bt (/home/username/Desktop/projectname/dist/server.js:1239:87385)
    at yt (/home/username/Desktop/projectname/dist/server.js:1239:87260)
    at ir (/home/username/Desktop/projectname/dist/server.js:1239:110031)
    at He.insertToken (/home/username/Desktop/projectname/dist/server.js:1239:86646)
    at /home/username/Desktop/projectname/dist/server.js:1239:89924
    at Mt (/home/username/Desktop/projectname/dist/server.js:1239:89939)
    at Ke (/home/username/Desktop/projectname/dist/server.js:1239:84920)
    at Object.parse (/home/username/Desktop/projectname/dist/server.js:1239:83906)
    at Object.t.createDocument (/home/username/Desktop/projectname/dist/server.js:3180:76668)
    at Object.t.createWindow (/home/username/Desktop/projectname/dist/server.js:3180:76772)
  ngTempTokenPath: null,
  ngTokenPath:
   [ 'function (){}',
     e { _desc: 'DocumentToken', ngMetadataName: 'InjectionToken' } ] }
Unhandled Promise rejection: StaticInjectorError[function (){} -> InjectionToken DocumentToken]:
  StaticInjectorError(Platform: core)[function (){} -> InjectionToken DocumentToken]:
    Right-hand side of 'instanceof' is not an object ; Zone: <root> ; Task: Promise.then ; Value: { TypeError: StaticInjectorError[function (){} -> InjectionToken DocumentToken]:
  StaticInjectorError(Platform: core)[function (){} -> InjectionToken DocumentToken]:
    Right-hand side of 'instanceof' is not an object
    at bt (/home/username/Desktop/projectname/dist/server.js:1239:87385)
    at yt (/home/username/Desktop/projectname/dist/server.js:1239:87260)
    at ir (/home/username/Desktop/projectname/dist/server.js:1239:110031)
    at He.insertToken (/home/username/Desktop/projectname/dist/server.js:1239:86646)
    at /home/username/Desktop/projectname/dist/server.js:1239:89924
    at Mt (/home/username/Desktop/projectname/dist/server.js:1239:89939)
    at Ke (/home/username/Desktop/projectname/dist/server.js:1239:84920)
    at Object.parse (/home/username/Desktop/projectname/dist/server.js:1239:83906)
    at Object.t.createDocument (/home/username/Desktop/projectname/dist/server.js:3180:76668)
    at Object.t.createWindow (/home/username/Desktop/projectname/dist/server.js:3180:76772)
  ngTempTokenPath: null,
  ngTokenPath:
   [ 'function (){}',
     e { _desc: 'DocumentToken', ngMetadataName: 'InjectionToken' } ] } TypeError: StaticInjectorError[function (){} -> InjectionToken DocumentToken]:
  StaticInjectorError(Platform: core)[function (){} -> InjectionToken DocumentToken]:
    Right-hand side of 'instanceof' is not an object
    at bt (/home/username/Desktop/projectname/dist/server.js:1239:87385)
    at yt (/home/username/Desktop/projectname/dist/server.js:1239:87260)
    at ir (/home/username/Desktop/projectname/dist/server.js:1239:110031)
    at He.insertToken (/home/username/Desktop/projectname/dist/server.js:1239:86646)
    at /home/username/Desktop/projectname/dist/server.js:1239:89924
    at Mt (/home/username/Desktop/projectname/dist/server.js:1239:89939)
    at Ke (/home/username/Desktop/projectname/dist/server.js:1239:84920)
    at Object.parse (/home/username/Desktop/projectname/dist/server.js:1239:83906)
    at Object.t.createDocument (/home/username/Desktop/projectname/dist/server.js:3180:76668)
    at Object.t.createWindow (/home/username/Desktop/projectname/dist/server.js:3180:76772)

Desired behavior

Is expected to render the application

epgeroy commented 6 years ago

any help is appreciated, thanks in advance

epgeroy commented 6 years ago

In addition, this are the scripts I'm using (most of them are boilerplate code posted on https://github.com/angular/angular-cli/wiki/stories-universal-rendering)

angular.json architect->server section

    "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/server",
            "main": "src/main.server.ts",
            "tsConfig": "src/tsconfig.server.json"
          }
        },

package.json relevant scripts

    "build:client-and-server-bundles": "ng build --prod && ng run projectname:server",
    "build:prerender": "npm run build:client-and-server-bundles && npm run webpack:server && npm run generate:prerender",
    "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server",
    "generate:prerender": "cd dist && node prerender",
    "webpack:server": "webpack --config webpack.server.config.js --progress --colors",
    "serve:prerender": "cd dist/browser && http-server",
    "serve:ssr": "node dist/server"

using npm run build:ssr && npm run serve:ssr to build and run

main.server.ts

export { AppServerModule } from './app/app.server.module';

app.server.module.ts

import {NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';
import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';

import {AppModule} from './app.module';
import { RootComponent } from '../root/root.component';

@NgModule({
  imports: [
    // The AppServerModule should import your AppModule followed
    // by the ServerModule from @angular/platform-server.
    AppModule,
    ServerModule,
    ModuleMapLoaderModule // <-- *Important* to have lazy-loaded routes work
  ],
  // Since the bootstrapped component is not inherited from your
  // imported AppModule, it needs to be repeated here.
  bootstrap: [RootComponent], // small change over here since this is the name of my bootstrap component
})
export class AppServerModule {}

tsconfig.server.json

{
    "extends": "../tsconfig.json",
    "compilerOptions": {
      "outDir": "../out-tsc/app",
      "baseUrl": "./",
      "module": "commonjs",
      "types": []
    },
    "exclude": [
      "test.ts",
      "**/*.spec.ts"
    ],
    "angularCompilerOptions": {
      "entryModule": "app/app.server.module#AppServerModule"
    }
  }

webpack.server.config.js

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {  server: './server.ts' },
  resolve: { extensions: ['.js', '.ts'] },
  target: 'node',
  // this makes sure we include node_modules and other 3rd party libraries
  externals: [/(node_modules|main\..*\.js)/],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [
      { test: /\.ts$/, loader: 'ts-loader' }
    ]
  },
  plugins: [
    // Temporary Fix for issue: https://github.com/angular/angular/issues/11580
    // for "WARNING Critical dependency: the request of a dependency is an expression"
    new webpack.ContextReplacementPlugin(
      /(.+)?angular(\\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      /(.+)?express(\\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
}
tomskip123 commented 6 years ago

+1

realmx commented 6 years ago

+1 same with me

ng -v

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/

Angular CLI: 6.0.1
Node: 8.11.0
OS: darwin x64
Angular: 6.0.1
... animations, cli, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.6.1
@angular-devkit/build-angular     0.6.1
@angular-devkit/build-optimizer   0.6.1
@angular-devkit/core              0.6.1
@angular-devkit/schematics        0.6.1
@ngtools/webpack                  6.0.1
@schematics/angular               0.6.1
@schematics/update                0.6.1
rxjs                              6.1.0
typescript                        2.7.2
webpack                           4.6.0
ghost commented 6 years ago

Setting mode: 'none' in webpack config solved this issue for me. But the bundle sized increased from 1.6Mb to 4.8Mb

akanass commented 6 years ago

+1

epgeroy commented 6 years ago

nice to read that @hitandyrun can you elaborate, I don't have a webpack.config file, also in this file webpack.server.config.js I don't have a settings mode entry. Where should I put this configuration?

Thanks in advance

realmx commented 6 years ago

@epgeroy https://webpack.js.org/concepts/mode/

akanass commented 6 years ago

@epgeroy like this :


module.exports = {
  mode: "none",
  ....
}
epgeroy commented 6 years ago

It works!! thanks a lot, I was just cracking my head on this one right now renders some dummy content as proof of concept, but goes like a charm

any ideas on why wont work with production settings?? or when it will?

tomskip123 commented 6 years ago

yes, just confirming this seems to be a fix. bundle size isn't that great (BIG project pumping out 8.4mb) but I suppose it doesn't matter seeing that it's running on the server. I guess file size isn't as big an issue because the client isn't downloading it. but still, if uglifying and compiling server code is going to improve server performance production compiling should be an option.

akanass commented 6 years ago

Here my configuration for universal:

"server": {
  "builder": "@angular-devkit/build-angular:server",
  "options": {
    "outputPath": "dist/server",
    "main": "src/main.server.ts",
    "tsConfig": "src/tsconfig.server.json",
     "fileReplacements": [
       {
         "replace": "src/environments/environment.ts",
         "with": "src/environments/environment.prod.ts"
       }
     ],
     "optimization": true,
     "sourceMap": false
  }
}

Like this we have an optimization for the build & the good environment.

ghost commented 6 years ago

This doesn't affect the server.ts file which is compiled using the webpack.server.config.js file mentioned above. This only affects the output of main.server.ts.

can-cc commented 6 years ago

@njl07 thanks, save my times

raghav-reglobe commented 6 years ago

Please try to build with webpack in development mode, you will get proper message to solve it. webpack --config webpack.server.config.js --mode development

pedlop commented 6 years ago

I only managed with the webpack --mode=none --config webpack.server.config.js

Kalpesh300 commented 6 years ago

@hitandyrun It works!! thanks a lot. I was moving my head around this one like hell.

patrickhousley commented 6 years ago

Is there anything on the roadmap to add a schematic so we do not have to have this additional webpack configuration file? Possibly treat the node server as an additional application? I would say in a perfect world, ng serve would even use the node server instead of webpack dev server. Should that be opened as a new feature request?

suau commented 6 years ago

Webpack in mode: "production" optimizes the output with certain defaults (If you don't set a mode, it is "production" by default). One optimization is including UglifyJsPlugin which will mangle class and functions names and break injection. You can (and should) keep production mode for all other optimizations. All of the following edits are made to your webpack.server.config.js file.

module.exports = {
  mode: "production",
  ...
}

and just disable UglifyJs

module.exports = {
  mode: "production",
  ...
  optimization: {
    minimize: false
  },
  ...
}

This does NOT affect the client side js bundles sent to the browser, just your server.js file running in node. However, if you really want the server.js to be minimized as well (I doubt that will have any impact on the performance at all) you can manually add UglifyJsPlugin back and enable keep_classnames and keep_fnames options.

module.exports = {
  mode: "production",
  ...
  optimization: {
    minimize: false
  },
  plugins: [
    new UglifyJsPlugin({
      parallel: true,
      uglifyOptions: {
        keep_classnames: true,
        keep_fnames: true
      }
    }),
    ...
  ]
  ...
}
nandowalter commented 6 years ago

Hi guys, for those who do not use webpack directly (this is my case, not having a typescript server file), a trick could be to disable optimization in angular.json config file

...
"configurations": {
  "production": {
    "optimization": false,
    "sourceMap": false,
    "namedChunks": false,
    "extractLicenses": true,
    "vendorChunk": false
  }
}
...

then npm install uglify-es package and launch optimization integrating a command in an npm script, defined in package.json file:

...
"scripts": {
    "build-ssr": "ng build --prod ssr && node_modules/.bin/uglifyjs dist/main.js -c -m --keep-classnames --keep-fnames -o dist/main.js"
  }
...

So you have more control on uglify settings and can distribute optimized server files.

seanmavley commented 6 years ago

@suau Thanks for the solution. Working for me. And I think I like the server part to even be with uglification. Makes no difference on performance.

I had the challenge with SSR in Angular, and mocked the document, window and localstorage, that's where I came across this issue. But disabling the optimization fixed it.

Thanks once again.

filipesilva commented 5 years ago

Thanks for reporting this issue. This issue was originally reported a long time ago and since then we've had many releases, one of which might have addressed this problem. Please update to the most recent Angular CLI version.

If the problem persists after upgrading, please open a new issue, provide a simple repository reproducing the problem, and describe the difference between the expected and current behavior.

servrox commented 5 years ago

Stumbled upon this issue when I tried to get webpack.server.config.js work in my nx workspace with a seperated nest app for ssr.. (fixed it -> Demo+Explanation) Maybe this helps someone.

angular-automatic-lock-bot[bot] commented 5 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.