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

Allow running prettier/formatting before writing to disk #2726

Open
SimenB opened this issue Oct 10, 2019 · 9 comments
Open

Allow running prettier/formatting before writing to disk #2726

SimenB opened this issue Oct 10, 2019 · 9 comments
Labels
core Related to codegen core/cli kind/enhancement New feature or request

Comments

@SimenB
Copy link
Contributor

SimenB commented Oct 10, 2019

Is your feature request related to a problem? Please describe.

After https://github.com/dotansimha/graphql-code-generator/releases/tag/v1.6.0, we've used a hook with afterAllFileWrite: prettier --write. The problem is that since this applies after files have been written to disk, all watchers are triggered even if the content is identical, then when that run is complete (riddled with lint errors that take a long time for webpack to render), the watcher is triggered again since the files have been formatted.

Describe the solution you'd like
A hook that runs before files are written to disk that allows us to format the content using the tool of our choice (e.g. prettier or eslint).

Describe alternatives you've considered
N/A

Additional context

N/A

@dotansimha
Copy link
Owner

@SimenB sounds like a good idea, but how can we pass the content to prettier without writing it to the disk?

@dotansimha dotansimha added the waiting-for-answer Waiting for answer from author label Oct 11, 2019
@SimenB
Copy link
Contributor Author

SimenB commented Oct 11, 2019

Maybe by having some sort of postprocess hook that's a module.

export function postprocess(content: string, filename: string): string;

So right before you write to disk, you pass it through this module that can manipulate content however it wants and returns a modified (or not) content that you then write to disk

@dotansimha dotansimha added core Related to codegen core/cli enhancement and removed waiting-for-answer Waiting for answer from author labels Oct 11, 2019
@SimenB
Copy link
Contributor Author

SimenB commented Jan 28, 2020

I tried looking into this now, and lifecycle hooks are a really bad fit - they want to spawn a binary and ignore anything it might want to return, and doesn't support running an arbitrary node script and passing it arguments. I'd have to add some executable to $PATH to achieve what I want, which is pretty bad DX I think. What I essentially want is to be able to format the string you hold in memory, so the currentHash === previousHash check passes and no file is written to disk.

const content = result.content || '';
const currentHash = hash(content);
let previousHash = recentOutputHash.get(result.filename);
if (!previousHash && exists) {
previousHash = hash(readSync(result.filename));
}
if (previousHash && currentHash === previousHash) {
debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
return;
}

I don't want to spend a bunch of time adding a completely new API without some input from the maintainers. My original idea was to just add a hook, but as mentioned, I don't think that fits the other hooks at all. But maybe we could add a new config called moduleHooks or something, which are required and executed?

@studds
Copy link

studds commented Feb 3, 2020

Here's an approach I've seen: https://github.com/ForbesLindesay/typescript-json-validator/blob/9538f99ea75967a7a6caf776bd3d1db986b21f1b/src/prettierFile.ts

If prettier is installed, it runs it. If not, it's a no-op. It doesn't do it in memory, but I'm not actually sure if that is a disadvantage.

@SimenB
Copy link
Contributor Author

SimenB commented Feb 3, 2020

I need it to run in memory to avoid the FS operation that triggers watchers. Or at least two FS operations triggering any watchers twice. What you've linked can be achieved currently via the afterOneFileWrite or afterAllFileWrite hooks

@bauwaerter
Copy link

I could be misunderstanding your issue, but couldn't you add all your generated files to a .prettierignore file?

@SimenB
Copy link
Contributor Author

SimenB commented Aug 17, 2020

I want the output to look pretty, though

@felixfbecker
Copy link

If the config file is a JS file or the API is used it would be great if we could just supply a function taking a string and returning a string (or Promise of a string) which we could easily pass prettier.format() to

@tmatz
Copy link

tmatz commented Jul 5, 2023

#8662 seems to have fulfilled this feature request.

codegen.ts

import * as prettier from 'prettier';

const prettierrcPath = path.resolve(__dirname, '.prettierrc');
const prettierignorePath = path.resolve(__dirname, '.prettierignore');
let prettierOptions: prettier.Options | null | undefined;

const codegen: CodegenConfig = {
  hooks: {
    beforeOneFileWrite: async (
      filepath: string,
      source: string
    ): Promise<string> => {
      if (prettierOptions === undefined) {
        prettierOptions = await prettier.resolveConfig(prettierrcPath);
      }
      const fileInfo = await prettier.getFileInfo(filepath, {
        ignorePath: prettierignorePath,
      });
      if (fileInfo.ignored) {
        return source;
      }
      return prettier.format(source, {
        ...prettierOptions,
        filepath,
      });
    },
  },
  ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Related to codegen core/cli kind/enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

6 participants