Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServerBuilder: allow to configure file-loader option emitFile #12878

Closed
enten opened this issue Nov 6, 2018 · 2 comments · Fixed by #15955
Closed

ServerBuilder: allow to configure file-loader option emitFile #12878

enten opened this issue Nov 6, 2018 · 2 comments · Fixed by #15955
Labels
area: devkit/build-angular freq1: low Only reported by a handful of users who observe it rarely severity2: inconvenient type: bug/fix
Milestone

Comments

@enten
Copy link

enten commented Nov 6, 2018

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search issues before submitting
- [x] feature request

Command (mark with an x)

- [ ] new
- [x] build
- [ ] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Versions

$ node --version
v8.9.4
$ npm --version
5.10.0
$ ng --version
Angular CLI: 7.0.2
Node: 8.9.4
OS: linux x64
Angular: 7.0.0
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.10.2
@angular-devkit/build-angular     0.10.2
@angular-devkit/build-optimizer   0.10.2
@angular-devkit/build-webpack     0.10.2
@angular-devkit/core              7.0.2
@angular-devkit/schematics        7.0.2
@angular/cli                      7.0.2
@ngtools/webpack                  7.0.2
@schematics/angular               7.0.2
@schematics/update                0.10.2
rxjs                              6.3.3
typescript                        3.1.3
webpack                           4.19.1

Repro steps

The main purpose is to build an universal angular application.

To achieve that we need two projects:

  • a first which uses @angular-devkit/build-angular:browser builder to create a bundle which will run in browser for client side rendering (more often called single page application) ;
  • a second which uses @angular-devkit/build-angular:server builder to create a bundle which will run in server with nodejs for server side rendering.

In addition, the bundle server serves statically the bundle browser assets.

The angular.json below show how to configure the build of the both bundles.

That works as expected and we can run our universal angular application.

But the bundle server includes every assets emitted by the file-loader which is common to the both webpack configs generated dynamically.

We doesn't need (and doesn't use/serve) that server assets because there are already present in the bundle browser: we can remove them and our application still works well.

{
  "$schema": "./node_modules/@angular-devkit/core/src/workspace/workspace-schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "angular": {
      "root": "",
      "projectType": "application",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/app/browser",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.browser.json",
            "assets": [
              {
                "glob": "favicon.ico",
                "input": "src",
                "output": "/"
              },
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "/assets"
              }
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/app/server",
            "main": "src/main.server.ts",
            "tsConfig": "src/tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "outputHashing": "media"
            }
          }
        }
      }
    }
  }
}

The log given by the failure

Below, that is the tree of the dist folder after build browser and server bundles for production.

dist
 `- app
     `- browser
         `- 3rdpartylicenses.txt
         `- favicon.ico
         `- foo-img.[hash].png
         `- index.html
         `- main.[hash].js
         `- polyfills.[hash].js
         `- runtime.[hash].js
         `- styles.[hash].css
     `- server
         `- foo-img.[hash].png
         `- main.js
         `- main.js.map

We can notice that foo-img.[hash].png exists in both browser and server folders because we import and use this image in app.component.ts.

// extract from app.component.ts
import FOO_IMG = require('./foo-img.png');


// extract from typings.d.ts
declare module '*.png' {
  const imagePath: string;
  export = imagePath;
}

Desired functionality

I think the architect server builder needs a new option which can set the file-loader option emitFile to false.

How about flag fileLoaderEmitFile which is true by default?

        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/app/server",
            "main": "src/main.server.ts",
            "tsConfig": "src/tsconfig.server.json",
+           "fileLoaderEmitFile": false
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "outputHashing": "media"
            }
          }
        },

Mention any other details that might be useful

In my opinion, some other file-loader options can be useful as outputPath.

But the emitFile option is required to optimize building.

@ngbot ngbot bot added this to the needsTriage milestone Nov 7, 2018
@alan-agius4 alan-agius4 added the freq1: low Only reported by a handful of users who observe it rarely label Nov 7, 2018
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Nov 7, 2018
@enten
Copy link
Author

enten commented Nov 8, 2018

Patch example which implements server builder option fileLoaderEmitFile (to apply after revision 13c057a).

diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts
index 5a33f1e3..84b1cb98 100644
--- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts
+++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts
@@ -65,6 +65,7 @@ export interface BuildOptions {
   lazyModules: string[];
   platform?: 'browser' | 'server';
   fileReplacements: CurrentFileReplacement[];
+  fileLoaderEmitFile?: boolean;
 }
 
 export interface WebpackTestOptions extends BuildOptions {
diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts
index 699dafdb..dd1b1323 100644
--- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts
+++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts
@@ -270,6 +270,7 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
           loader: 'file-loader',
           options: {
             name: `[name]${hashFormat.file}.[ext]`,
+            emitFile: 'fileLoaderEmitFile' in buildOptions ? buildOptions.fileLoaderEmitFile : true,
           },
         },
         {
diff --git a/packages/angular_devkit/build_angular/src/server/schema.d.ts b/packages/angular_devkit/build_angular/src/server/schema.d.ts
index 24b57542..5bfd94fb 100644
--- a/packages/angular_devkit/build_angular/src/server/schema.d.ts
+++ b/packages/angular_devkit/build_angular/src/server/schema.d.ts
@@ -132,6 +132,11 @@ export interface BuildWebpackServerSchema {
  * Enable and define the file watching poll time period in milliseconds.
  */
   poll?: number;
+  /**
+   * Enable emit files from the file-loader. If false, the file-loader will return
+   * a public URI but will not emit files.
+   */
+  fileLoaderEmitFile?: boolean;
 }
 
 /**
diff --git a/packages/angular_devkit/build_angular/src/server/schema.json b/packages/angular_devkit/build_angular/src/server/schema.json
index 119d4909..30bd5045 100644
--- a/packages/angular_devkit/build_angular/src/server/schema.json
+++ b/packages/angular_devkit/build_angular/src/server/schema.json
@@ -169,6 +169,11 @@
     "poll": {
       "type": "number",
       "description": "Enable and define the file watching poll time period in milliseconds."
+    },
+    "fileLoaderEmitFile": {
+      "type": "boolean",
+      "description": "Enable emit files from the file-loader. If false, the file-loader will return a public URI but will not emit files.",
+      "default": true
     }
   },
   "additionalProperties": false,

vikerman pushed a commit that referenced this issue Oct 30, 2019
… server build

The server should serve the assets emitted by the browser builder. In fact the nguniversal schematics are configured to serve the assets from the browser folder
https://github.com/angular/universal/blob/a0cc9ab97a70370eff872664ac46391a193aa45e/modules/express-engine/schematics/install/files/__serverFileName%40stripTsExtension__.ts#L26

Closes #12878
@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Nov 30, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: devkit/build-angular freq1: low Only reported by a handful of users who observe it rarely severity2: inconvenient type: bug/fix
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants