Skip to content

Allow exclusion of files / folders from being watched by @angular-devkit/build-angular:application (ESBuild + Vite) #26644

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

Closed
mirobo opened this issue Dec 12, 2023 · 10 comments
Labels
needs: more info Reporter must clarify the issue

Comments

@mirobo
Copy link

mirobo commented Dec 12, 2023

Command

serve

Description

According to https://angular.io/guide/esbuild it says:
The usage of Vite, much like the Webpack-based development server, is encapsulated within the Angular CLI dev-server builder and currently cannot be directly configured.

Webpack previously allowed a customWebpackConfig and therefore it was possible to exclude certain files and folders from the "watch" mechanism. With Vite this option is completely gone. In bigger setups with lots of libraries and Cypress/Jest tests residing in the folder of each library, the app gets rebuilt every time an irrelevant file (i.e. my-test.e2e.spec.ts, my-test.spec.ts or my-test.cy.ts) was changed.

Especially creating and editing Cypress tests becomes a real an absolute struggle because you have to wait for the build to be completed before you can run a test properly.

What I also find strange is this line: https://github.com/angular/angular-cli/blob/main/packages/angular_devkit/build_angular/src/builders/dev-server/vite-server.ts#L483

So where is the actual "watching" done, if not by Vite itself? Haven't found other hints..

Describe the solution you'd like

Ideas

Describe alternatives you've considered

No response

@alan-agius4
Copy link
Collaborator

The watching is indeed not done by Vite, but this is done as part of the application builder implementation, a rebuild only happens when a file that is referenced in the application is modified.

Can you provide the output of ng version?

@mirobo
Copy link
Author

mirobo commented Dec 12, 2023

Thanks, sure:

Angular CLI: 17.0.0
Node: 18.14.0
Package Manager: npm 9.3.1
OS: win32 x64

Angular: 17.0.2
... animations, common, compiler, compiler-cli, core, elements
... forms, language-service, platform-browser
... platform-browser-dynamic, router

Package                          Version
----------------------------------------------------------
@angular-devkit/architect        0.1700.0
@angular-devkit/build-angular    17.0.0
@angular-devkit/core             17.0.0
@angular-devkit/schematics       17.0.0
@angular-devkit/schematics-cli   16.0.4
@angular/cdk                     17.0.0
@angular/cli                     17.0.0
@angular/material                16.2.12 <--- i'm aware of this one :D 🙏 
@schematics/angular              17.0.0
ng-packagr                       17.0.0
rxjs                             7.8.1
typescript                       5.2.2
zone.js                          0.14.2

To give you a clearer view:
We have 170+ buildable libraries and each library has a folder "src" with the actual code and a folder "cypress" which contains e2e-tests, pageobjects, and so on. Then we have Jest- and Cypress-Component-Tests that are within the "src" folder, right besides each specific component or util.

Everytime I change a pageobject, e2e-test, jest-test or one of the Cypress-tests generates an output within that library (i.e. "my-lib/reports"), a rebuild was triggered with webpack (and also with vite).

Edit:
This was my exclusion list

module.exports = {
  watchOptions: {
    ignored: [
      '**/node_modules',
      '**/cypress/*',
      '**/reports/*',
      '**/dist/*',
      '**/jest-cache/*',
      '**/reports/*',
      '**/jest.config.ts',
      '**/.eslintrc.json',
      '**/tsconfig.*json',
      '**/cypress.config.ts',
      '**/*.MD',
      '**/test-setup.ts',
      '**/coverage/*',
      '**/.nyc_output/*',
      '**/*.spec.ts',
      '**/*.cy.ts',
      '**/*.test.ts',
      '**/libs/shared/e2e/*',
      '**/libs/shared/test/*',
      '**/myapp-e2e/*'
    ]
  }
};

@alan-agius4
Copy link
Collaborator

In the past, we didn't offer support for excluding files from the watcher, and it's not a feature we intend to introduce. However, it does seems there might be a bug in ng-packagr causing a library rebuild when a non-compilation file like my-lib/reports is modified, resulting in an unnecessary application build.

If this is the case, I recommend filing an issue on https://github.com/ng-packagr/ng-packagr/.

@mirobo
Copy link
Author

mirobo commented Dec 14, 2023

I'm trying to figure out how the files are marked as files to consider in the build with ESBuild.

In build-action.js, I added some code to log the files that triggered a change:

const packageWatchFiles = [
            // manifest can affect module resolution
            'package.json',
            // npm lock file
            'package-lock.json',
            // pnpm lock file
            'pnpm-lock.yaml',
            // yarn lock file including Yarn PnP manifest files (https://yarnpkg.com/advanced/pnp-spec/)
            'yarn.lock',
            '.pnp.cjs',
            '.pnp.data.json',
        ];
        watcher.add(packageWatchFiles.map((file) => node_path_1.default.join(workspaceRoot, file)));
>>>>>
        result.watchFiles.forEach((f) => {
            if(/.*\.spec.ts/.test(f)) {
                console.log(f);
            }
        });
>>>>>

I see that spec-Files and totally unrelated files show up here. Using --verbose on the serve command I also see that unrelated HTML-files trigger a rebuild (they were stored within a libs-folder there other Angular libs reside).

The search led me to https://github.com/angular/angular-cli/blob/main/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-execution-result.ts#L91 and codeBundleCache here https://github.com/angular/angular-cli/blob/main/packages/angular_devkit/build_angular/src/builders/application/execute-build.ts#L69

But then it gets blurry. I see the reference to the evn variable NG_BUILD_WATCH_ROOT, but I didn't set this variable.

From the side of ESBuild I didn't find out anything.. I see that you can give ESBuild entrypoints, but that's it. I don't see how other files are included in the watched files..

@alan-agius4
Copy link
Collaborator

Likely this is caused by some misconfiguration in your project:

  • If you are using tailwinds css make sure that the content glob is not picking up the spec files.
  • In your tsconfig file make sure that you don't include the spec files.

@mirobo
Copy link
Author

mirobo commented Dec 15, 2023

We have TSConfigs that necessarily reference spec files and Cypress tests. The setup is done with NX:

tsconfig.json in the root folder of the library:

{
  "extends": "../../../../tsconfig.base.json",
  "include": [],
  "files": [],
  "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    },
    {
      "path": "./cypress/tsconfig.json"
    }
  ]
}

and then tsconfig.spec.json and cypress/tsconfig.json include Jest- and Cypress-Tests but have different settings for the types, (for cypress/tsconfig.json -> "types": ["cypress", "node", "cypress-axe"],).

When I running nx/ng serve it seems that only the main "tsconfig.app.json" is respected anyways (I saw this because in one library there was a problem with an import using require, so I switched it to CommonJS (because there seem to be no alternatives for https://github.com/nx-js/compiler-util -> I fixed it with import { compileCode, expose } from '@nx-js/compiler-util/dist/cjs.es6.js';). When doing a build, it would respect the tsconfig.json of that very library and when running serve it would respect tsconfig.app.json. I had to add esModuleInterop to both configs.

So I don't understand how the TSConfigs would affect the file watcher and how I could check how it is affecting the watcher.

But thanks to your hints I found the culprit: The Tailwind configuration.

It not documented very well on their website and according to some older issues, it seems that exclusions are not possible:

But NX, with its default setup, generates globPatterns that have some sort of exclusion: **/!(*.stories|*.spec).{ts,html}

Not I can extend this glob pattern and possibly create an MR for NX to extend these exclusions per default (to also match cypress.config.ts, my-util.test.ts, my-other-test.cy.ts).

As for now I'll ignore my huge ignore list for webpack and go on with the fixed Tailwind content globs and observe how the new watcher behaves with other files (as you see code-coverage output generated by Cypress was also a problem).

Last problem to solve now is using @media screens(xs) {..} or the old @screens xs {..} in SCSS-files with angular plugin-sass:

image

.twscreentest {
    background-color: red;
    font-size:40px;
    // @screen xs {
    //  background-color: blue;
    // }

    @media screen (sm)  {
        font-size:80px;
      }
  }

Previously we used @screen which still is supported (but not documented anymore) and it works just fine with the Webpack bundler. Maybe it works because of some very well hidden configuration in that setup.

In a new setup I tried it with Tailwind 3.0.2, 3.3.5 and 3.3.6 and none of these options work..

Possibly yet another misconfiguration.. :-(

@alan-agius4
Copy link
Collaborator

Glad to hear that you managed to fix the watching issues. The sass error is expected and valid in this case and is being thrown by the Sass compiler.

echo ".twscreentest { @media screen (sm){ font-size:80px;}}" | npx sass --stdin
Error: expected "{".
  ╷
1 │ .twscreentest { @media screen (sm){ font-size:80px;}}
  │                               ^
  ╵
  - 1:31  root stylesheet

@alan-agius4 alan-agius4 closed this as not planned Won't fix, can't repro, duplicate, stale Dec 15, 2023
@mirobo
Copy link
Author

mirobo commented Dec 15, 2023

Is this a fundamental misunderstanding from my side? I thought I could use @screen within SCSS. But I guess I need to study https://tailwindcss.com/docs/using-with-preprocessors#nesting and see what should actually work and what shouldn't.

But still, it is very confusing because our setup works with Webpack and Tailwind (I don't know why it works) and it doesn't work with ESBuild. So something in the bundler must have changed too, since I didn't update Tailwind in my real project. Any ideas/hints other than to delete everything Tailwind-related and start from scratch? 😅

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Dec 15, 2023

This should not work when when using SCSS with both webpack and esbuild based builder. This is because the Sass compiler runs before Tailwind and the latter is only invoked if the Sass compilation is successfully.

In this cases the error is correct, the fact that it worked, was likely a bug in the Sass compiler that was fixed.

Example of the error with Webpack when using Angular CLI version 17

$ ng build 
✔ Browser application bundle generation complete.

./src/styles.scss - Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
expected "{".
  ╷
6 │   @media screen (sm)  {
  │                 ^
  ╵
  src/styles.scss 6:17  root stylesheet

./src/styles.scss?ngGlobalStyle - Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
HookWebpackError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
expected "{".
  ╷
6 │   @media screen (sm)  {
  │                 ^
  ╵
  src/styles.scss 6:17  root stylesheet

@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 Jan 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs: more info Reporter must clarify the issue
Projects
None yet
Development

No branches or pull requests

2 participants