-
-
Notifications
You must be signed in to change notification settings - Fork 36
Consider a simpler API #85
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
Comments
Yeah. I agree things can be simpler. Sent #81 and #83 to start on that.
Going away with #75
@manuel3108 @AdrianGonz97 you may be interested in this idea as I just saw you discussing something like #67 (comment)
Something to do with how community adders are executed. The thing that has been taking my attention is that we have a very big API surface area. I've been putting together some PRs today trying to shrink it down, but even still I'm rather nervous that we'll want to change something in the future. I'd like to see if we can't make community adders more standalone (#77) |
funnily enough, this would solve my qualm with #67 (comment)
we need to pass conditionals so that certain packages are installed only under certain conditions. for instance, see the tailwind cli/packages/adders/tailwindcss/config/adder.ts Lines 21 to 35 in 59ddada
this is being worked on in a different way. see #33 and #75 edit: oh, ben answered too. i guess github decided to not live update the comments today 🙃 |
since we're downloading and unpacking the community packages manually, it'll require us to resolve all of their dependencies as well. this is a solvable problem. it's just not a priority atm and I expect it to be a pain in the ass to do when the time comes 😄 for now, community packages can just bundle their deps if they desperately need them |
But that would be part of the context passed to the Another option could be something along these lines: export default defineIntegration({
description: 'An adder template demo',
environments: { kit: true, svelte: true },
options: {
demo: {
question: 'Do you want to use a demo?',
type: 'boolean',
default: false
}
},
setup: ({ api, options }) => {
if (options.demo) {
api.createFile('adder-template-demo.txt', 'This is a text file made by the integration template demo!', {
force: true // if false or unspecified, errors if file exists
});
}
api.updateFileIfExists('src/DemoComponent.svelte', (file) => {
const { script, css, generateCode } = parseSvelte(file.content);
file.addImport('../adder-template-demo.txt?raw', 'default', 'Demo');
imports.addDefault(script.ast, '../adder-template-demo.txt?raw', 'default', 'Demo');
return generateCode({...});
});
}
}); The details of the APIs aren't important here (related: I find the |
(For that matter I'm not sure we would need things like |
yes, but are you suggesting that adders should be the ones that update the
I much prefer what you originally proposed - that's getting closer to my ultimate vision of having a tsmorph-like api that performs string manipulations behind the scenes (so we don't have to faff around with generating code from ASTs, which is the leading cause of all of our formatting woes). something like this would be ideal: import { defineIntegration } from '@sveltejs/cli/integration';
export default defineIntegration({
description: 'An adder template demo',
environments: { kit: true, svelte: true },
options: {
demo: {
question: 'Do you want to use a demo?',
type: 'boolean',
default: false
}
},
files: ({ options, kit }) => [
{
name: 'adder-template-demo.txt',
content: (content) => {
if (content) return content; // leave alone
if (options.demo) {
return 'This is a text file made by the integration template demo!'
}
}
},
{
name: `${kit.routes}/+layout.svelte`,
condition: !!kit,
content: (content) => {
return content || '<slot />';
}
},
{
name: `${kit.routes}/+page.svelte,
condition: !!kit,
content: (content) => {
const { script, css, generateCode } = parseSvelte(content);
script.importNamed('../adder-template-demo.txt?raw', { demo: 'Demo' });
css.addClass('foobar', { 'background-color': 'blue' });
return generateCode({ script: script.generateCode(), css: css.generateCode() });
}
{
]
}); after authoring a whole bunch of adders, this really does feel like the right level of abstraction.
i think this would be going too 'low level'. adders shouldn't be messing around with |
I'm not saying it doesn't warrant special attention, just that this... setup: ({ api, options }) => {
api.addDevDependency('tailwindcss', '^3.4.9');
api.addDevDependency('autoprefixer', '^10.4.20');
if (options.plugins.includes('typography')) {
api.addDevDependency('@tailwindcss/typography', '^0.5.14');
}
if (options.prettier) {
api.addDevDependency('prettier-plugin-tailwindcss', '^0.6.5');
}
} ...feels a lot more flexible and future-proof to me than this: packages: [
{ name: 'tailwindcss', version: '^3.4.9', dev: true },
{ name: 'autoprefixer', version: '^10.4.20', dev: true },
{
name: '@tailwindcss/typography',
version: '^0.5.14',
dev: true,
condition: ({ options }) => options.plugins.includes('typography')
},
{
name: 'prettier-plugin-tailwindcss',
version: '^0.6.5',
dev: true,
condition: ({ prettier }) => prettier
}
] You never know what satanic logic people are going to need to implement, and it's a hell of a lot easier for them to do so if they don't need to contort everything into a
There's a bug in your code. If setup: ({ file, options, kit }) => {
if (options.demo) {
file.createIfNotExists('adder-template-demo.txt', 'This is a text file made by the integration template demo!');
}
if (!!kit) {
file.createIfNotExists(`${kit.routes}/+layout.svelte`, '<slot />');
file.update(`${kit.routes}/+page.svelte`, (content) => {
const { script, css, generateCode } = parseSvelte(content);
script.importNamed('../adder-template-demo.txt?raw', { demo: 'Demo' });
css.addClass('foobar', { 'background-color': 'blue' });
return generateCode({ script: script.generateCode(), css: css.generateCode() });
})
}
} It's significantly less code, much easier to follow (to me), and if I want to do something like rename a file then I don't have to figure out what that looks like declaratively (if we're really not keen on letting people use |
ahh, okay. that's certainly more reasonable than what I had imagined. i like it!
i wrote that entirely outside of the editor, but the lsp would've caught that 😄
damn, that really is quite clean. alright, I'm convinced! what do you guys think @benmccann @manuel3108 ? |
Yeah, I agree that I might call it I'd probably import |
We're also duplicating the metadata for community adders. It's declared in the adder itself and in https://github.com/sveltejs/cli/tree/main/community-adders |
most of these (with the exception of if the metadata was not present in our registry, then we'd have to fetch all of their |
My reasoning was threefold:
But yes, there are trade-offs. And I haven't really given any thought into what would go into the API. |
Per #84 — let's treat this as a private implementation detail and put the public API design on the backburner for now |
To help kick the can down the road, I'd suggest that we bundle all packages together into |
It feels like we can make the API simpler. Why isn't the community template just this, for example?
Things to note:
src
directoryid
andname
have been removed. They don't need to be separate concepts — it's less confusing if we just use anid
consistently, instead of leaving people who see 'Foo Bar' listed somewhere to wonder whether it'sfoobar
orfoo-bar
or whatever. And for stuff onnpm
, the package name is theid
, I'd argue we don't need another (that could potentially be something different than the package name, which is another source of confusion). Maybe there's an argument for mandating anid
for programmatic usage but I think it's probably unnecessarydescription
andenvironments
moved up to the top level instead of being inmetadata
packages
array. Surelypackage.json
can be just like any other JSON file? The smaller the API surface area the betterfiles
is a function that returns an array, instead of an array of objects. That way it's easier to put logic in one place (e.g. you can doconst ext = options.typescript ? 'ts' : 'js'
once instead of in eachname
method, and easier to return a different set of files entirely under certain conditionscontentType
is inferred from file extension (I don't know if this is possible to do reliably from a types perspective, just an idea)addImport
are passed in rather than imported. The big downside here is that it slightly discourages you from extracting the logic out into separate functions, but I'd argue a) this is a context where less indirection is better anyway, and b) it's outweighed by the benefits of discoverability and not having to deal with the exposed guts of things likejsAst
unless you absolutely have toRelated note: What's the technical reason for the prohibition on dependencies? Seems very restrictive
The text was updated successfully, but these errors were encountered: