observablehq / framework

A static site generator for data apps, dashboards, reports, and more. Observable Framework combines JavaScript on the front-end for interactive graphics with any language on the back-end for data analysis.
https://observablehq.com/framework/
ISC License
2.41k stars 111 forks source link

Allow overriding the output root with a command line flag #1390

Closed mythmon closed 3 months ago

mythmon commented 4 months ago

This can be helpful if you are building in an environment that is different than the configuration file expected. It can also be used to build a project multiple times to multiple directories, such as to run diff on the output to see the effect of a change.

It would however make any "custom" scripting between build and deploy harder, since the output root is no longer as predictable. Perhaps the recommendation here should instead be to make the config file read an environment variable for its output directory?

mbostock commented 4 months ago

I have been wondering if we should have a more general way of overriding the config. For example config overrides would allow the checked-in configs for the examples to be simpler, while allowing us to still apply a shared example header when building/deploying. I also wonder if such a thing isn’t already possible: maybe a config file that imports and augments another config file? (Maybe relying only on process.cwd?)

mythmon commented 4 months ago

What if we could "layer" config files? In docker-compose, you can pass --file multiple times to specify multiple configuration files. Each file implicitly extends the one that came before it.

So for this example, we could have an extra file that only specifies export default { output: "override" }. You could then say observable build --config observablehq.config.js --config override.js. Values in override.js would override those from the normal config.

That gets tricky for compound settings like pages. Since our configs are code though, we could have them participate actively in the overlay process:

export default (config) => ({
  ...config,
  // remove all but top level pages
  pages: config.pages.filter(d => !d.path),
});

Here I'm using a "return a new modified object" approach, but maybe it would be simpler to make the interface require mutating the config object. I'm not picky about how exactly the function works.

This might also be able to take care of #1389, if we make the location of deploy.json configurable.