TL; DR:我正在尝试使用Angular Elements作为Angular应用程序的插件。如果我用--prod
它构建元素,则可以ng serve
在我的应用程序上使用它(开发设置),但是当我ng serve --prod
在我的应用程序上使用它或应用程序之后ng build --prod
(生产设置)使用它时,它将进入无限重载。
不过,如果我构建添加元素--optimization=false
,则可以与我的生产性应用程序一起使用,但不适用于我的开发设置。
关键是,我期待的是建立一个角形元件用--prod
就可以了,对于两种情况。
问题:有没有办法解决这个问题?
现在,长时间阅读。
在工作中,我们尝试在Angular站点中使用可配置的插件,在该站点中,服务器是告知哪个插件处于活动状态的服务器。
我们试图动态地加载Angular模块,但这又是另一回事,我们把它搁置了一天。
因此,除非我们以应有的方式构建所有内容,否则我们接下来要尝试的就是Angular Elements。
首先,我开始遵循本教程https://scotch.io/tutorials/build-a-reusable-component-with-angular-elements/amp,并忽略了有关的所有内容,okta
因为我的功能有所不同。
创建:
我使用下一条命令创建了核心应用程序,这将是托管插件的应用程序:
ng new core --routing --skip-git --style scss --skip-tests --minimal
然后,我使用以下命令创建了一个插件/角度元素:
ng new plugin --skip-git --style scss --skip-tests --minimal
插入:
创建完所有内容后,我进入了插件并在中对此行进行了注释polyfills.ts
,在该站点的某处阅读到它可以解决NgZone
已经加载的问题,这是事实:
// import 'zone.js/dist/zone'; // Included with Angular CLI.
在tsconfig.json
我换"target": "es5"
到"target": "es2015"
为了解决某个问题如何角创建元素。不太确定它是如何工作的,但是stackoverflow提出了建议,并且成功了。
我app.module.ts
根据本教程中的一些想法和类似的内容编辑了如下内容,但丢失了链接:
import { BrowserModule } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA, Injector, NgModule } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
],
providers: [
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
],
entryComponents: [
AppComponent,
],
})
export class AppModule {
constructor(private injector: Injector) {
const elem = createCustomElement(AppComponent, { injector: this.injector });
customElements.define('my-plugin', elem);
}
ngDoBootstrap() {
}
}
注意:我添加了CUSTOM_ELEMENTS_SCHEMA
“原因是我在某个地方找到了它,但是它并没有解决它(而且,我不确定它能做什么)。
在中,app.component.ts
我这样做是为了在其模板中显示一些属性:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
public content: any = {
a: 10,
b: '20',
}
}
而app.component.html
看起来像这样:
Some content:
<pre>{{content | json}}</pre>
在package.json
文件中,我有三个脚本来构建所有脚本:
{
"scripts": {
"build": "npm run build:opt && npm run build:noopt",
"build:opt": "ng build --prod --output-hashing none && node build-elements.js",
"build:noopt": "ng build --prod --output-hashing none --optimization=false && node build-elements.noopt.js"
}
}
该文件build-elements.js
如下所示(build-elements.noopt.js
具有不同的目标名称的文件相同):
'use strict';
const concat = require('concat');
const fs = require('fs-extra');
const path = require('path');
(async function build() {
const files = [
'./dist/plugin/runtime.js',
'./dist/plugin/polyfills.js',
'./dist/plugin/scripts.js',
'./dist/plugin/main.js',
];
const destinationDir = path.join(__dirname, '../core/src/assets');
await fs.ensureDir(destinationDir);
await concat(files, path.join(destinationDir, 'my-plugin.js'));
})();
核心:
对于主机应用程序,我添加了一个名为的组件embedded
,并且默认路由使用了该组件。
然后,我embedded.component.html
使用一些Bootstrap类将变成了类似的内容:
<div id="embedded-container" class="container border border-primary rounded mt-5 p-3" #container>
<pre>Loading...</pre>
</div>
最后,embedded.component.ts
最终像这样显示了实际的加载机制:
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { environment } from '../../environments/environment';
@Component({
selector: 'app-embedded',
templateUrl: './embedded.component.html',
})
export class EmbeddedComponent implements OnInit {
@ViewChild('container') public container: ElementRef;
constructor(protected activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.activatedRoute.queryParams.subscribe((params: Params) => {
const script = document.createElement('script');
if (params['how-it-should-be'] !== undefined) {
script.src = environment.production ? '/assets/my-plugin.js' : '/assets/my-plugin-no-optimization.js';
} else {
script.src = environment.production ? '/assets/my-plugin-no-optimization.js' : '/assets/my-plugin.js';
}
document.body.appendChild(script);
const div = document.createElement('div');
div.innerHTML = '<my-plugin></my-plugin>';
this.container.nativeElement.innerHTML = '';
this.container.nativeElement.appendChild(div);
});
}
}
运行:
如果我运行ng serve
并浏览到http://localhost:4200
,则页面加载不会出现问题,注入插件,将新元素添加到DOM并显示来自插件的消息。而且,如果您调试该应用程序,则会看到它已加载/assets/my-plugin.js
,该应用程序是为生产而构建的。除了进行调试之外,这不是问题。
然后,如果我运行ng serve --prod
(或将其构建用于生产),它也可以正常工作,但会加载/assets/my-plugin-no-optimization.js
,该文件是为“调试”而构建的。
这是我最终在实际应用程序上使用的解决方案,但是如您所见,我没有在插件中使用经过优化的代码进行生产,这根本不好。。。
为了证明我的观点,如果我浏览至http://localhost:4200/?how-it-should-be
,它将尝试为加载优化的插件,为加载ng serve --prod
调试的插件ng serve
。请注意,这将使您陷入无限重载,请打开浏览器开发人员工具进行查看。
我们使用的最终产品要复杂得多,但是这些示例具有无法真正发挥作用的基本逻辑。
我还以此创建了一个GitHub存储库,您可以在其中查看这些代码,并尝试自己解决问题,或者以示例的方式提出自己的想法。
如果您想知道如何使用--optimization=false
kinda修复它,那么,我正在尝试调试此问题(事实证明这是不可能的),然后突然加载了它。
我查看了一下时间,对于生产部署来说,我来得太迟了两个小时,所以我添加了这种丑陋的机制来根据环境加载不同的构建。它在开发和生产中都有效,但是我对此并不感到骄傲。
抱歉,如果我的英语不好...不,不,我的英语不好,对不起^ __ ^
我找到了解决方案!
事实证明,问题在于在同一个上下文中运行多个webpack项目。我对问题的理解实质上是,当您使用webpack构建项目时,它们会在运行时进行一些webpack引导,并依赖于全局上下文(webpackJsonp
)中定义的特定功能。当多个webpack配置尝试在同一DOM上下文中进行自举时,它将创建此处定义的症状。(在这里找到更详细的解释-https: //github.com/angular/angular/issues/23732#issuecomment-388670907)
这个GitHub注释描述了一个解决方案,但没有介绍方法-https: //github.com/angular/angular/issues/30028#issuecomment-489758172。下面,我将展示我是如何具体解决的。
我们可以使用webpack配置为我们的Web组件重命名webpackJsonp,以使两个Angular项目(或任何使用webpack构建的项目)都不会相互干扰。
解
首先,我们安装@ angular-builders / custom-webpack软件包,以使我们能够在Angular CLI中修改内置的webpack配置。
npm install --save-dev @angular-builders/custom-webpack
接下来,我们更新angular.json文件,以使用新的构建器和名为的选项中的新属性值customWebpackConfig
。这包括我们将要创建的新文件的路径以及mergeStrategy。这种合并策略表示我们想将配置附加到output
webpack配置部分。
angular.json
...
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js",
"mergeStrategies": { "output": "append"}
},
...
最后,我们只需将extra-webpack.config.js
文件添加到包含angular.json的目录中即可。该文件仅包含以下内容:
module.exports = {
output: {
jsonpFunction: '<webcomponent-prefix>-webpackJsonp'
}
}
如果将其更改为其他值,则jsonpFunction
默认值为webpackJsonp
,它将起作用。我决定保留函数名称,但为Web组件应用程序添加前缀。从理论上讲,您可以在相同的DOM上下文中运行N个Webpack配置,只要每个配置都有唯一的jsonpFunction
再次构建您的Web组件,瞧,它起作用了!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句