棱角分明的树摇晃不剥离开发代码,我应该寻找什么东西



我使用的是所有与Angular相关的软件包的最新版本(所以Angular 10)。

我想向组件添加一些代码,但我只希望这些代码存在于开发中,而不是存在于生产版本中。它需要在生产构建中完全剥离。我发现了这条评论,这表明环境会自动执行此操作(因为它们const)。

我尝试在我的应用程序中使用该确切的代码,但开发代码仍然存在于生产版本中。我将代码复制到我用ng new制作的新测试应用程序中,它在那里确实可以正常工作。

我应该寻找什么东西,我该如何解决这个问题?这可能是因为我有 CommonJS 依赖项,如果是这样,我可以对此做任何事情(因为我无法删除这些依赖项)?

一些注意事项:

  • 这里在 angular-cli 存储库上打开了一个问题。
  • environment对象永远不会写入代码库中的任何位置,我已经彻底搜索过了。(无论如何,它只在少数地方使用。
  • if (false) { }为界的代码已正确剥离。
  • environment{.prod}.ts末尾删除服务导出并不能解决问题。
  • 删除所有 CommonJS 依赖项并不能解决问题。

这是environment.prod.ts(environment.ts是一样的,只是用false而不是true):

export const environment = {
production: true
};
export * from './services/services';

以下是我正在测试的main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { environment } from 'environments/environment';
import { AppModule } from './app/app.module';
// tslint:disable:no-console
if (environment.production) {
console.warn('this is a prod build');
enableProdMode();
}
if (!environment.production) {
console.warn('this is a dev build');
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));

以下是运行ng build -c my-prod-config后的相关输出代码:

o.X.production && (console.warn('this is a prod build'), Object(i.R) ()),
o.X.production || console.warn('this is a dev build'),
s.d().bootstrapModule(fi).catch (e=>console.error(e))

以下是angular.json的相关部分:

"my-prod-config": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"stylePreprocessorOptions": {
"includePaths": [
"src/styles"
]
},
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"baseHref": "./"
}

这是tsconfig.base.json

{
"compileOnSave": false,
"compilerOptions": {
"downlevelIteration": true,
"importHelpers": true,
"module": "es2020",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"baseUrl": "src/",
"experimentalDecorators": true,
"allowJs": true,
"target": "es2015",
"lib": [
"es2018",
"dom"
],
"paths": {
"path1": [
"app/modules/stripped-from-stack-overflow-example1"
],
"path2": [
"app/modules/stripped-from-stack-overflow-example2"
]
}
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictTemplates": true,
"strictInjectionParameters": true
}
}

这是package.json

{
"name": "my-app",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"section stripped": "section stripped"
},
"private": true,
"dependencies": {
"@angular/animations": "10.0.8",
"@angular/common": "10.0.8",
"@angular/compiler": "10.0.8",
"@angular/core": "10.0.8",
"@angular/forms": "10.0.8",
"@angular/platform-browser": "10.0.8",
"@angular/platform-browser-dynamic": "10.0.8",
"@angular/router": "10.0.8",
"@ng-idle/core": "9.0.0-beta.1",
"@ng-idle/keepalive": "9.0.0-beta.1",
"@ngneat/until-destroy": "8.0.1",
"angular-svg-icon": "10.0.0",
"brace": "0.11.1",
"caniuse-lite": "1.0.30001111",
"chart.js": "2.9.3",
"core-js": "3.6.5",
"css-vars-ponyfill": "2.3.2",
"detect-browser": "5.1.1",
"element-closest-polyfill": "1.0.2",
"file-saver": "2.0.2",
"fomantic-ui": "2.8.6",
"jsonexport": "3.0.1",
"moment": "2.24.0",
"ngx-drag-drop": "2.0.0",
"rxjs": "6.6.2",
"tslib": "^2.0.0",
"typeface-roboto": "0.0.75",
"uuid": "8.3.0",
"zone.js": "0.10.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "0.1000.5",
"@angular/cli": "10.0.5",
"@angular/compiler-cli": "10.0.8",
"@angular/language-service": "10.0.8",
"@types/chart.js": "2.7.54",
"@types/file-saver": "2.0.1",
"@types/uuid": "8.0.1",
"codelyzer": "^6.0.0",
"rimraf": "3.0.2",
"rxjs-tslint-rules": "4.34.0",
"ts-node": "8.10.2",
"tslint": "6.1.3",
"tslint-angular": "3.0.2",
"typescript": "3.9.7",
"webpack-bundle-analyzer": "3.8.0"
}
}

您可以应用与environment.ts相同的逻辑;创建main.prod.ts(没有特定于开发的代码)和main.dev.ts(使用特定于开发的代码),然后在配置中使用fileReplacements

prod 的配置将是:

"fileReplacements": [
...
{
"replace": "src/main.ts",
"with": "src/main.prod.ts"
}

您链接到的帖子特别指出,"由 if 语句中的常量控制的代码"会发生树摇动。因此,您可能需要将 if 语句更改为:

if (environment.production===true) {
console.warn('this is a prod build');
enableProdMode();
}
else    
{
console.warn('this is a dev build');
}

引入常量的存在。

这个问题由 Angular 团队成员在 GitHub 上回答。答案是这是一个 Webpack 问题 - 如果环境文件被导入到多个输出文件中,那么 Webpack 无法正确优化它。我在下面粘贴了完整的回复以供后人使用。

没有复制品,很难辨别确切的原因。但是,潜在的原因是在多个生成的输出文件中使用了环境JS模块(environment.ts/environment.prod.ts)。如果在主代码和惰性路由的代码中使用环境模块,则可能出现这种情况。发生这种情况时,Webpack 无法将环境模块与主模块连接起来(就像在新项目中发生的那样),因为环境模块需要可供两个不同的输出模块访问。这反过来又会阻止优化程序内联生产属性值,因为环境对象现在实质上是从另一个模块导入的,而不是局部变量。

发生这种情况时,类似于以下内容的代码(表示单独的 Webpack 模块)应最终出现在应用程序的主输出文件中:

AytR: function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.d(__webpack_exports__, "a", function () {
return environment;
});
const environment = { production: !0 };
},

我不知道你的环境出了什么问题,但似乎你不需要做任何事情,生产构建会解决这个问题。

例如,我测试了一个带有以下代码的组件:

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'test1';
constructor() {
console.log('A');
if (environment.production) {
console.log('B');
} else {
console.log('C');
}
console.log('D');
if (!environment.production) {
console.log('E');
} else {
console.log('F');
}
console.log('G');
}
}

然后我跑ng build --prod.这就是组件的构造函数在输出代码中被丑化的方式:

{class t{constructor(){this.title="test1",console.log("A"),console.log("B"),console.log("D"),console.log("F"),console.log("G")}}

请注意,if 条件和控制台.log('C') 和 console.log('E') 不在输出中。

这就是它在 es5 输出中的发射方式:

(Wu=function n(){v(this,n),this.title="test1",console.log("A"),console.log("B"),console.log("D"),console.log("F"),console.log("G")})
再次是 if 条件和控制台.log(">

C")和控制台.log("E")

因此,只需使用 --prod 标志进行构建即可解决它,除非您的环境中出现问题。

我们知道environment.ts 文件将在生产构建期间被 environment.prod.ts 文件替换。您已在 app.component.ts 条件中编写了 if else 语句,这些条件将在运行时进行评估,并且不会摇晃树。

我想建议一种替代的本地方法。创建两个名为 lib-dev 和 lib-prod 的库项目。 使用ng g library lib-prod&ng g library lib-dev创建库项目。 在库项目中创建所需的模块、组件和服务。确保两个库项目中的组件选择器、模块和服务名称应相同。

lib-prod 和 lib-dev 的 package.json 中的名称应该相同。

{
"name": "my-lib",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^10.0.0",
"@angular/core": "^10.0.0"
}
}

tsconfig.json

....
"paths": {
"my-lib": [
"dist/my-lib"
],
"extension/*": [
"dist/my-lib/*"
]
}

在您的 app.module.ts 中使用编译的库项目。

import { MyLibModule } from "dist/my-lib";
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
.....
MyLibModule
],
providers: [
],
bootstrap: [AppComponent]
})
export class AppModule { }

主应用程序的包.json

{
"name": "demandfarm-ngweb",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng build lib-dev && ng serve",
...
"build:prod": "ng build lib-prod && ng build --prod "
},

对于开发人员,npm run start命令将首先编译lib-dev库项目,然后运行ng serve。 它将在主应用程序中使用编译lib-dev

对于生产,npm run build:prod命令将首先编译lib-prod库项目,然后运行ng build --prod

相关内容

最新更新