Thursday, 28 June 2018

How can I get Angular Universal to Compile Typescript for Firebase Cloud Functions

I'm trying to add Angular Universal to my Angular Firebase app. I've been following along with this video. But needed to make some changes in order to get it to work with cloud functions.

I have added an additional block of config to the "apps" array in angular-cli.config

// .angular-cli.config.json - "apps" [
{
      "platform": "server",
      "root": "src",
      "outDir": "dist/server",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.server.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.server.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "serviceWorker": false,
      "styles": [
        "styles/styles.scss"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
}

Next I have also added an additional file called 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"
  }
}

I then created an extra app.server.module.ts

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

@NgModule({
  imports: [
    AppModule,
    ServerModule,
    ServerTransferStateModule, //  <-- needed for state transfer
    ModuleMapLoaderModule // <-- needed for lazy-loaded routes,
  ],
  declarations: []
})
export class AppServerModule {}

Like the above video, the code gets transpiled into a dist folder for a browser app and server app. Although I have decided to avoid using webpack to create the server.js file and instead decided to add this to my cloud functions directly as typescript.

ng build --prod && ng build --prod --app 1 --output-hashing=false

creates..

  dist/browser
  dist/server

Instead of server.js I've moved the code to cloud functions.js. However importing my server bundle from dist/server/main.bundle.js will cause the firebase deploy process to Error.

// cloud functions code above...

// Causes Error: -> const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./../../dist/server/main.bundle');

// more cloud functions code below..

The Error I recieve is:

i  functions: preparing functions directory for uploading...

Error: Error occurred while parsing your function triggers.
project_root/node_modules/angular2-markdown/markdown/markdown.component.js:1
(function (exports, require, module, __filename, __dirname) { import { Component, ElementRef, Input } from '@angular/core';

  • I believe my cloud functions is only using node 6.
  • The dist/server/main.bundle.js requires a node_module that uses es6 import syntax.

    dist/server/main.bundle.js -> require("angular2-markdown.. -> markdown.component.js:1 -> import <-- { Component,

  • I've already tried asking the functions tsconfig.json to bring the output to es5, but I don't think it can manipulate the node_module .js dependencies to be a lower js. (The node_modules are 1 folder higher than the node_modules in the functions folder - (The dist folder is also 1 level higher above the functions folder))

functions/tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5", // <--- Trying to es5 the output
    "typeRoots": [
      "node_modules/@types",
      "src/types-overwrite"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}

  • Is it possible to get firebase cloud functions to upgrade the node version to use the import syntax like Node 10.5?
  • If not is there a way I can just edit my tsconfig to just get everything to transpile to es5?

Update:

I've created an example github project to download and test the function deployment.

Link: https://github.com/Jonathan002/firebase-cloud-functions-node-6-import-statement-broken/blob/master/README.md

I have also tried to bundle everything as web code using webpack, but have gotten the error:

TypeError: o.initStandalone is not a function

I believe it comes from a firebase node_module being depended on, but I haven't been able to confirm this. (This error only appears on the larger non-example project I'm working on and it was hard to determine exactly what node_module to include to get it to be built with webpack).

Shown below though is the webpack config I used in functions:

var path = require('path');

module.exports = {
  entry: './src/index.ts',
  target: 'node',
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, 'lib')
  },
  mode: 'none',
  devtool: 'source-map',
  plugins: [],
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.json']
  },
  module: {
    rules: [
      { test: /\.tsx?$/, loader: 'ts-loader' },
    ]
  },
};

When in the functions folder, you can generate the web code using:

webpack --config webpack.config.js --colors --progress

and removing the predeploy code with firebase's typescript functions in firebase.json:

{
  "functions": {
    "predeploy": [
      // remove this..
      // -> "npm --prefix \"$RESOURCE_DIR\" run lint",
      // -> "npm --prefix \"$RESOURCE_DIR\" run build"
    ]
  }
}



from How can I get Angular Universal to Compile Typescript for Firebase Cloud Functions

No comments:

Post a Comment