guybedford / chomp

'JS Make' - parallel task runner for the frontend ecosystem with a JS extension system.
https://chompbuild.com
Apache License 2.0
143 stars 7 forks source link

Discussion: what are expectations wrt config files existing in the project root dir? #21

Closed canadaduane closed 2 years ago

canadaduane commented 2 years ago

The Big Question

Given that Chomp creates, reads, modifies or ignores (depending on the context, see examples below) config files in the project root, what should a developer expect from Chomp? How can we make the rules clear, the problems easy to explain (if any), and minimize negative surprise?

Example 1: package.json

With an empty project folder and a chompfile.toml below, running chomp svelte will create a package.json file with "svelte": "^3.45.0" as a devDependency. This procedure seems to assume certain things about the project--for example that the package.json does not exist, or is valid JSON, or has sane configuration.

Interesting Edge Cases:

  1. If a pre-existing package.json file exists with an incompatible version of svelte specified (e.g. "2.0.0"), what should happen? (Currently, "ERR_UNSUPPORTED_DIR_IMPORT" is thrown by ESMLoader).
  2. What should happen if the package.json file is invalid? For example, if it has comments in it and npm cannot process it. (Currently, an "EJSONPARSE" error is produced).
  3. What should happen if the package.json file has changed in a way that makes the compile step valid or invalid? For example, changing a package.json file with "svelte": "2.0.0" to "svelte": "^3.45.0" (with 2.0.0 installed in node_modules) will not install svelte 3.45.0, and will fail to compile with ERR_UNSUPPORTED_DIR_IMPORT.

Example 2: svelte.config.js

In a "regular" svelte project, there is a svelte.config.js file that configures svelte compiler and preprocessor options. Currently, Chomp ignores this file and directly transforms (compiles) svelte files into js and css via a template specific to svelte.

Questions:

  1. If a developer expects the svelte.config.js file to do something (for example, accept "sass" format for <style> tags), but the file is ignored, how can we signal to the developer that it is ignored?
  2. How would they go about configuring svelte if it is ignored?
  3. If it should not be ignored, how does that affect our current chomp:svelte template? And how can we best balance simplicity and configurability?

Sample chompfile.toml:

version = 0.1

[[task]]
  name = "svelte"
  template = "chomp:svelte"
  target = "lib/#.js"
  deps = ["src/#.svelte"]
guybedford commented 2 years ago

I quite like the idea of moving as much logic and configuration into the Chompfiles and templates as possible.

For the npm template, it will check that the lockfile exists and that the package.json exists and run npm init -y if the package.json does not exist. So it's using standard npm processes, it's just triggering them automatically.

So I would suggest updating the npm template to support version verification, possibly with a user prompt if a version change will occur.

For configuration files, I was just working on the Babel template, and there's a lot of benefits to defining eg presets and plugins in the template itself. This is the Babel + TypeScript initialization:

[[task]]
  template = "babel"
  target = "out.js"
  deps = ["in.js"]
  [task.args]
    presets = ['@babel/preset-typescript']

The above will then automatically depend on the npm install template and ensure that Babel and the preset is installed.

Extending the configuration options in this way is useful because it means each task can have its own options - you can have multiple configurations in the same application working together, whereas singular configuration files make this harder.

For Svelte I would thus suggest we start to extend the svelte.config.js configurations into the Chompfile template arguments - there can be no limit to the dynamicism of templates as they are JS, so we can do a lot of magic and passing of options here. Basically anything you can do in a config file you can achieve in a template argument.

guybedford commented 2 years ago

If you want to experiment with template customization for Svelte, you can copy the svelte.toml template body into your local chompfile from the templates directory in this repo. The local version will then override the default template.

guybedford commented 2 years ago

Added https://github.com/guybedford/chomp/issues/22 for npm versioning checks.

I've pushed an update to rename chomp:svelte to just svelte in the template name. I've also explicitly inlined the version in the install script.

guybedford commented 2 years ago

Another good approach is to make all of this configurable.

For npm install: version_verify: true, init: false sorts of options.

For svelte: svelteConfig: true.

canadaduane commented 2 years ago

I like your goal to move as much logic and config to chompfiles in the majority of cases. I think 80% of chomp build requirements could be handled this way. But also as you noted, there is likely some "escape hatch" needed for complexity.

What if we had two "modes of operation":

  1. A chomp task works behind the scenes: In this mode, Chomp guarantees not to touch anything in the project directory--all of its operations happen in its own tucked-away area somewhere (e.g. /tmp, or a .chomp directory in current project)
  2. A chomp task is "porous" to config files: In this mode, a Chomp task will work with and use current package.json, and other config files such as .babelrc, svelte.config.js, etc.

For example, the [[task]]'s configuration could be ignore_config_files: true by default (mode 1) and false (mode 2) if integration with config files is needed (more complex case).

This seems like a "best of both worlds" approach: keep it simple for most cases, but integrate with complex scenarios where needed.

canadaduane commented 2 years ago

My motivation for two modes is that it was surprising that Chomp decided to create a package.json file for me, a package-lock.json file, and install things in node_modules as well. The cognitive burden it added was: "Oh dear, magic happened, and I need to now work backwards to figure out what it did."

guybedford commented 2 years ago

All good points, I've posted a PR in https://github.com/guybedford/chomp/pull/25 that addresses these concerns.

guybedford commented 2 years ago

I've going to close this as resolved in #25 for now.

TLDR; by default rc configurations are used, with the ability to disable that, and with a configFile option for .js configuration files to be used. In addition installs verify unless explicitly using autoInstall = true.

Please reopen / repost if I'm missing anything else.