Angular Universal 不适用于 Angular Google 地图

Angular Universal does not work with Angular Google Maps

技术:Angular Cli,Angular 版本 7,Angular Google 地图,Firebase 函数。

问题:我正在尝试为我的 angular 通用应用程序提供服务,但在构建时出现 angular google 地图错误。

错误 我得到:

/Users/test/Public/Leisure/leisure-app/functions/node_modules/@agm/core/services/managers/info-window-manager.js:1
(function (exports, require, module, __filename, __dirname) { import {
Observable } from 'rxjs';
                                                              ^^^^^^

SyntaxError: Unexpected token import
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)

似乎 Angular Universal 不喜欢第三方库。

我关注的资源: https://hackernoon.com/deploying-angular-universal-v6-with-firebase-c86381ddd445

我的应用程序模块:

import { AgmCoreModule } from '@agm/core';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireDatabase } from '@angular/fire/database';
import { AngularFireModule } from '@angular/fire';
import { ServiceWorkerModule } from '@angular/service-worker';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { BrowserModule } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
import { GooglePlaceModule } from 'ngx-google-places-autocomplete';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { NgModule, NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { NgxErrorsModule } from '@hackages/ngxerrors';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { TruncateModule } from 'ng2-truncate';
import { MetaModule } from '@ngx-meta/core';
import { PreventDoubleSubmitModule } from 'ngx-prevent-double-submission';

// Core App
import { AppComponent } from './app.component';
import { CoreInterceptor } from './interceptor';
import { environment } from '../environments/environment';

// Modules
import { SharedModule } from './shared/shared.module';
import { CoreModule } from './services/core.module';
import { LayoutModule } from './layouts/layout.module';

// Sections
import { COMPONENTS } from './components/index';
import { ROUTES } from './app.routes';

// Guards
import { AuthGuard } from './guards/auth.guard';
import { CreditGuard } from './guards/credit.guard';

@NgModule({
  declarations: [
    AppComponent,
    COMPONENTS
  ],
  imports: [
    CommonModule,
    FormsModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireAuthModule,
    AngularFirestoreModule,
    AngularFireStorageModule,

    // This is the Angular google maps module causing issue on build
    AgmCoreModule.forRoot({
      apiKey: environment.googleApiKey,
      libraries: ['places']
    }),

    GooglePlaceModule,
    LayoutModule,
    BrowserModule.withServerTransition({ appId: 'test123' }),
    PreventDoubleSubmitModule.forRoot(),
    TruncateModule,
    MetaModule.forRoot(),
    HttpClientModule,
    NgxErrorsModule,
    ReactiveFormsModule,
    RouterModule.forRoot(ROUTES),
    CoreModule,
    SharedModule,
    ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: CoreInterceptor, multi: true },
    AuthGuard,
    CreditGuard,
    AngularFireDatabase
  ],
  exports: [ RouterModule ],
  schemas: [ NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

命令 I 运行: serve: npm 运行 build && firebase serve --only functions

最新错误(对于 npm 运行 serve:ssr):

来自 serve:ssr 的错误代码:

e.Lb=function(a,b,c){a=this.ka.J[String(a)];if(!a)return!0;a=a.concat();for(var d=!0,f=0;f<a.length;++f){var g=a[f];if(g&&!g.Sa&&g.capture==b){var k=g.listener,p=g.Ob||g.src;g.Eb&&this.Le(g);d=!1!==k.call(p,c)&&d;}}return d&&0!=c.Be};e.jb=function(a,b,c,d){return this.ka.jb(String(a),b,c,d)};var ub=h.JSON.stringify;function vb(a,b){this.Sf=100;this.ef=a;this.ug=b;this.Zb=0;this.Pb=null;}vb.prototype.get=function(){if(0<this.Zb){this.Zb--;var a=this.Pb;this.Pb=a.next;a.next=null;}else a=this.ef();return a};vb.prototype.put=function(a){this.ug(a);this.Zb<this.Sf&&(this.Zb++, a.next=this.Pb, this.Pb=a);};function I(){this.lc=this.Va=null;}var xb=new vb(function(){return new wb},function(a){a.reset();});I.prototype.add=function(a,b){var c=this.Af();c.set(a,b);this.lc?this.lc.next=c:this.Va=c;this.lc=c;};I.prototype.remove=function(){var a=null;this.Va&&(a=this.Va, this.Va=this.Va.next, this.Va||(this.lc=null), a.next=null);return a};I.prototype.wg=function(a){xb.put(a);};I.prototype.Af=function(){return xb.get()};function wb(){this.next=this.scope=this.Gc=null;}
wb.prototype.set=function(a,b){this.Gc=a;this.scope=b;this.next=null;};wb.prototype.reset=function(){this.next=this.scope=this.Gc=null;};function yb(a){h.setTimeout(function(){throw a;},0);}var zb;

TL;DR:

Source codeDEMO


这里的问题是 @agm/core 包是用 es2015 模块编译的。结果在js代码中包含importexport

要解决这个问题,您有两个主要选择:

1。将@agm/core包编译成commonjs格式。

您可以使用 babel 或 typescript 来编译该包。然后你需要确保你在你的函数 dependencies

中提供了编译版本

functions/package.json

"dependencies": {
  ...
  "@agm/core": "file:./@agm/core"
},

这里我使用的是本地依赖,你也可以使用自己发布的版本

另一种方法是直接在node_modules中编译并发布整个node_modules(我会避免这种情况):

firebase.json

{
  "functions": {
    "ignore": []
  }
}

如何编译?

通天塔

在根目录中安装依赖项。

npm i -D @babel/cli @babel/core @babel/preset-env

使用以下脚本编译:

package.json

"postbuild": "babel node_modules/@agm/core -d functions/@agm/core --presets @babel/preset-env && node ./copy-package-json.js"

哪里

copy-package-json.js

const fs = require('fs-extra');
const { join } = require('path');

(async() => {
  await fs.copy(join(process.cwd(), 'node_modules/@agm/core/package.json'),
                join(process.cwd(), 'functions/@agm/core/package.json'));
})();

打字稿

tsconfig.agm.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./functions/@agm/core",
    "types": [],
    "module": "commonjs"
  },
  "include": [
    "node_modules/@agm/core"
  ]
}

package.json

"postbuild": "tsc -p tsconfig.agm.json --allowJs && node ./copy-package-json.js"

2。生成服务器包

这是 Angular universal tutorial 使用的 我更喜欢这个解决方案.

也关注这个quide

简单步骤:


1.安装全局依赖项

我已经安装:

  • @angular/cli@7.3.8
  • firebase-tools@6.5.2

2。创建一个新的 Angular 项目

ng new angular-agm

3。添加Angular通用

ng add @nguniversal/express-engine --clientProject angular-agm

4.更新server.ts

导出 express 应用程序,然后删除对 listen 的调用并将索引更改为 index2。

import 'zone.js/dist/zone-node';
import {enableProdMode} from '@angular/core';
// Express Engine
import {ngExpressEngine} from '@nguniversal/express-engine';
// Import module map for lazy loading
import {provideModuleMap} from '@nguniversal/module-map-ngfactory-loader';

import * as express from 'express';
import {join} from 'path';
import * as path from 'path';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
export const app = express();

// const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');

const index = require('fs')
  .readFileSync(path.resolve(DIST_FOLDER, 'index2.html'), 'utf8')
  .toString();

const domino = require('domino');
const win = domino.createWindow(index);
global['window'] = win;
global['document'] = win.document;

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main');

// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));

app.set('view engine', 'html');
app.set('views', DIST_FOLDER);

// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
  maxAge: '1y'
}));

// All regular routes use the Universal engine
app.get('*', (req, res) => {
  res.render('index2', { req });
});

// Start up the Node server
/*app.listen(PORT, () => {
  console.log(`Node Express server listening on http://localhost:${PORT}`);
});*/

5.构建

npm run build:ssr

其中 build:ssr

"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server && node ./tools/copy-artifacts.js",

复制-artifacts.js

const fs = require('fs-extra');
const { join } = require('path');

(async() => {
  const src = join(process.cwd(), 'dist');
  const copy = join(process.cwd(), 'functions/dist');

  await fs.rename(join(src, 'browser/index.html'), join(src, 'browser/index2.html'));
  await fs.remove(copy);
  await fs.copy(src, copy);
})();

6.更新 functions/index.js 以使用 express app

的内置版本
const functions = require('firebase-functions');

const { app } = require('./dist/server');

exports.ssr = functions.https.onRequest(app);

7.配置firebase.json

{
  "hosting": {
    "public": "dist/browser",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "ssr"
      }
    ]
  }
}

源代码可以在Github

上找到

另请参阅演示 https://angular-agm.firebaseapp.com/