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

Programmatic Interface #9

Open
moltar opened this issue Feb 5, 2022 · 13 comments
Open

Programmatic Interface #9

moltar opened this issue Feb 5, 2022 · 13 comments

Comments

@moltar
Copy link

moltar commented Feb 5, 2022

Would be great to have a programmatic interface to integrate into other projects.

I'd like to use it with projen.

@kettanaito
Copy link
Member

Hey, @moltar. That's an interesting idea. Do you have some imaginary API in mind that we could expose to help you implement this?

Internally, this library just maps a single declaration file to multiple sources (jest, webpack, etc.). All mapping functions can be described as:

function map(config: AliasConfig): any

But as I understand, you want to use some sort of API so that dotailas would know about your custom mapping and then expose you the result?

I've looked at projen, and it looks like higher-level tooling. You should be able to use dotalias with any frameworks/project generators without issues, as dotalias exposes you configs to insert into the individual tools right away.

@moltar
Copy link
Author

moltar commented Feb 7, 2022

Do you have some imaginary API in mind that we could expose to help you implement this?

The original API is almost fine, I think.

The only issue is that it will throw if it can't find the source paths.

dotalias/src/index.ts

Lines 10 to 12 in 45d6f43

if (!result) {
throw new Error(`Failed to configure path alias: configuration not found.`)
}

So, maybe alias can be a fn that accepts paths, or defaults to discovering them.


alias({ foo: '../foo' }).jest
alias({ foo: '../foo' }).WebpackPlugin
// ...

I've looked at projen, and it looks like higher-level tooling. You should be able to use dotalias with any frameworks/project generators without issues, as dotalias exposes you configs to insert into the individual tools right away.

Right, almost there.

The only thing is that projen does not commit the config files to the filesystem, until all configs are synth'ed in memory.

We can access the config in memory (tsconfig object) during synth, and I could pass it to alias. But currently alias assumes that it will read the files from the filesystem.

I am proposing that alias should be able to accept existing path config as a parameter without reading anything from disk.

@kettanaito
Copy link
Member

Thanks for the examples! It's much more clear now.

I think we can create a new config API which would act as you've described:

  1. Accept an explicit configuration of paths;
  2. Produce the alias-compatible API, exposing the generated configurations for Jest, webpack, etc.
import { config } from 'dotalias'

const alias = config({
  server: '../packages/server/'
})

alias.jest
alias.WebpackPlugin

It's important we keep the actual usage identical to the one you get with using alias that reads the paths from the configuration files in the file system.

One question I have is how should the config behave if there is a .alias configuration file in your project? Should it merge two configs, giving the one you pass to config() the priority? Should it replace the config?

@moltar
Copy link
Author

moltar commented Feb 8, 2022

IMO in programmatic use case everything should be explicit without any side effects, e.g. no reading from disk.

@kettanaito
Copy link
Member

Yeap, in favor with you on that 👍

Nice, I think we have the API worked out. Would you be interested in opening a pull request with the draft implementation? I could use your help with this.

@moltar
Copy link
Author

moltar commented Feb 9, 2022

Certainly can try.

One thing I am not sure of, is how to handle this part:

dotalias/src/index.ts

Lines 10 to 12 in 45d6f43

if (!result) {
throw new Error(`Failed to configure path alias: configuration not found.`)
}

Since this is in the global scope, this will always throw in the programmatic use case, and it's kind of impossible to hide it now, since index exports alias that is already resolved.

@kettanaito
Copy link
Member

We can start by moving what's currently in index.ts to alias.ts. The index module will then point to both alias and new configure:

src/
  index.ts
  alias.ts
  configure.ts

This won't solve the global-scope configuration check just yet. We have two options:

Make alias a function, so that reading configuration happens when it's invoked.

Pros:

  • Encapsulated configuration reading/handling and related errors;

Cons:

  • A breaking change;
  • Loses a singleton nature; configured will be read everytime you call alias().

Use a Proxy around the alias object.

This only retain the current API but still requires some sort of memorization of the configuration so we don't read it multiple times.

Expose alias as an explicit import.

As in:

import { alias } from 'dotalias/alias'

This can also be dotalias/runtime or similar.

This way we scope the config reading to that explicit import, instead of exporting alias from the root-level index.ts.

Actually, I think this may be a good solution for config:

import { config } from 'dotalias/config'

config({ ... })

I'd recommend this option. The config module can be built separately and required to be imported directly, circumventing all the logic from alias.

What do you think?

@moltar
Copy link
Author

moltar commented Feb 10, 2022

Sure, I was considering all these options too, but wasn't sure if breaking change was an option.

Not a huge fan of:

import { config } from 'dotalias/config'

But I think that might be the best option in this case.

Similar patterns exist already, e.g. see:dotenv/config.

@moltar
Copy link
Author

moltar commented Feb 10, 2022

Another thought...

Might be beneficial to expose programmatic API for each converter independently.

The downside is to that approach is that it exposes (right now) internal API, and then makes it harder to move away from it later.

But the benefit is that if you only need one converter, then you don't need to call all other converters to get the full alias object back.

Thoughts?

@kettanaito
Copy link
Member

So basically make toJest and other converters public?

@moltar
Copy link
Author

moltar commented Feb 11, 2022

Yeah.

Because, for example, for our use case, we have no use for Webpack, so it's just extra CPU cycles to create an instance.

@kettanaito
Copy link
Member

kettanaito commented Feb 11, 2022

Then I suppose it's a replacement for config(), is that correct?

I can see both APIs being useful but I'd start with the one that immediately covers your use case.

I'm all hands for the following thing:

import { toRollup, toJest } from 'alias/config'

const config = { foo: '../bar/foo' }

const aliasOptions = toRollup(config)
const jestMapperOptions = toJest(config)

Would that be the functionality you're looking for?

By the way, I don't think there's particular trouble exporting the internal converters. I'd pretty much like to do so if it helps people achieve their goals. Converters are not complex and implement the same call signature.

@moltar
Copy link
Author

moltar commented Feb 14, 2022

import { toRollup, toJest } from 'alias/config'

Yup, that's what we are looking for!

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

2 participants