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

Hooks running twice on build #8795

Open
Spenhouet opened this issue Jan 30, 2023 · 11 comments
Open

Hooks running twice on build #8795

Spenhouet opened this issue Jan 30, 2023 · 11 comments
Milestone

Comments

@Spenhouet
Copy link

Describe the bug

Pretext
I have some expensive preprocessing methods which need to run on build of my static website.
I first tried executing them in svelte.config.js but I couldn't use typescript there, then I tried vite.config.ts but had other issues, then from inside the +layout.server.ts but noticed that for my build this is called 15 times (this seems to be expected behavior, see: #6728).

@KTibow on the Svelte Discord recommended me to use hooks.server.ts instead (https://kit.svelte.dev/docs/hooks).


I put my data preprocessing code directly inside the hooks.server.ts without any of the hook handlers since they all seem for different purposes than what I need.
I need my scripts to execute only once during build.

At the top I put a console.log which also prints Math.random().
During a build I get this print twice.

Once after the console output for the prerendered pages:
image

And another time after the build completed.
image

The last one seems a bit odd to me. Why does it need to run again after it already completed the build?

Reproduction

  1. Create a src/hooks.server.ts with a console.log(hook execution ${Math.random()})
  2. Run npm run build / vite build
  3. Look at the build log

Logs

N/A

System Info

System:
  OS: Linux 5.10 Ubuntu 20.04.4 LTS (Focal Fossa)
  CPU: (16) x64 12th Gen Intel(R) Core(TM) i5-12600K
  Memory: 11.97 GB / 15.50 GB
  Container: Yes
  Shell: 5.0.17 - /bin/bash
Binaries:
  Node: 18.12.1 - ~/.nvm/versions/node/v18.12.1/bin/node
  npm: 8.19.2 - ~/.nvm/versions/node/v18.12.1/bin/npm
npmPackages:
  @sveltejs/adapter-static: ^1.0.0 => 1.0.0 
  @sveltejs/kit: ^1.0.1 => 1.0.1 
  @sveltejs/vite-plugin-svelte: ^2.0.2 => 2.0.2 
  svelte: ^3.55.0 => 3.55.0 
  vite: ^4.0.3 => 4.0.3

Severity

serious, but I can work around it

Additional Information

No response

@Rich-Harris
Copy link
Member

This is expected - the server code is initialized once for analysis, so that the optimal client bundle can be built, and once for prerendering once we have the optimal client bundle.

If you need to do some processing before building happens then your hooks file is the wrong place for it, it should go in a separate script. If TypeScript is non-negotiable then just use ts-node.

@Spenhouet
Copy link
Author

Spenhouet commented Jan 31, 2023

But I also need svelte-kit features and want to use the same code I'm using in svelte.
So a hook handler that is executed only once would be much appreciated. Sounds doable to me.

@dummdidumm
Copy link
Member

Could you give a little more detail on what exactly your preprocessing thing does, and what SvelteKit features it's using and why?

@Spenhouet
Copy link
Author

It's precompiling data for prerendered pages.
It's currently using svelte imports like $app/paths or $env/static/private.
I also have a lot of shared code which is used during preprocessing but also on pages and endpoints of the svelte application.
I don't want to duplicate this code.
With the project I also already have a fully working setup with configs for typescript, vite, tests, package.json, ......... and I really don't want to duplicate this either.

@Rich-Harris
Copy link
Member

Are you writing out to the filesystem? Can you bail if the file already exists?

@Spenhouet
Copy link
Author

That is my current workaround. Every file (of many) gets a timestamp and I check if this timestamp was within a predefined time and bail if below that.
But I really hoped to not require that workaround.

Is providing a "onBuild" hook handler within the hooks.server.ts which gets executed once during build that much out of question?
When going through open and closed issues there are quite some with people trying to do similar things via different ways be it running in svelte.config.js, vite.config.js, layout.server.ts. And I found some on people being surprised that files get executed multiple times.
Feels like providing some official hook/method/... for this use-case would be beneficial to some and from my speculation might be an easy thing to provide? Or are there drawbacks?

@Rich-Harris
Copy link
Member

When going through open and closed issues there are quite some with people trying to do similar things via different ways

Can you point to some examples? It would be good to have a broad understanding of use cases before committing to an approach

@Spenhouet
Copy link
Author

Spenhouet commented Jan 31, 2023

Not everyone has the same use-case. But overall, I do feel there is a question of "where to put a one time executed script which should run at the start / build".

On script execution (in svelte.config.js, vite.config.js, ...)

I assume people who just request for there to be a .ts version of the config, that they want that due to more code in there and not just for the config part.

On multi time execution I was sure I came accross multiple issues with people being confused on the matter but searching now, every one has diverse use-cases like e.g. this one: #6728

@Rich-Harris Rich-Harris added this to the soon milestone Jan 31, 2023
@Spenhouet
Copy link
Author

I might have a complication here.
Within the hooks.server.ts I'm also copying files to /static.
When running build, it runs the hooks.server.ts and successfully copies all files to /static but after that on prerendering fails to find the referenced static files Error: 404 ... (linked from /).
When running build again, the files are already there and it runs through.

But at the time it fails, it should actually already have the files. So this seems a bit odd.
It must be something that is done before the hooks.server.ts call which is then used afterwards and does not know the static files.
On the build system this then fails every time since it never finds the files.

Reproduction:

  1. Use static adapter
  2. Have a page with a reference to a static file
  3. Have that page prerendered
  4. Have a file in another directory
  5. In hooks.server.ts perform a copy of that file to the /static folder
  6. Make sure the file is not in the static folder prior to the next step
  7. Run npm run build
  8. It should fail.

I thought this might be something to take into consideration in this issue.
If this is unexpected and should be looked at independently, I can open a separate bug report with reproduction project.

@DoisKoh
Copy link

DoisKoh commented Mar 8, 2023

I have a conditional process.exit(1) in my hooks.server.ts that is based on environment variables. In my CI, those variables are not set as they would be in production and so my build actually exits with error code 1. I know I can workaround this by adding more checks but they would be specifically for building in the CI (logic that I'd prefer to keep out hooks.server.ts) so doing that as a workaround feels iffy to me.

@dummdidumm
Copy link
Member

There's import { building } from '$app/environment' which is designed for use cases like this, so you don't need additional CI flags.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants