Code Monkey home page Code Monkey logo

astro-integration-kit's Introduction

Hi all! 👋

  • 🔭 I'm a French web fullstack developer working as a freelancer. I love Open-Source and I've been an Astro maintainer since December 2023.
  • 🌱 I’m currently learning XState, Clean Architecture and Testing
  • 👨‍💻 I deeply enjoy working with Astro, Typescript and Tailwind CSS to craft quality websites and interfaces.
  • 👉 You can find out more info and other social links on my website.

A few Astro projects:

Visitors

Stats

florian-lefebvre

astro-integration-kit's People

Contributors

adammatthiesen avatar brycerussell avatar florian-lefebvre avatar fryuni avatar jdtjenkins avatar ktym4a avatar lilnasy avatar schalkneethling avatar thejackshelton avatar totto2727 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

astro-integration-kit's Issues

Util that can create and read files from a hidden folder in the user's project

This is more of an RFC I guess, but what do we think about a utility that lets the author create and read files inside a hidden folder just for that integration inside a user's project?

So it'd be something like this:

({ createHiddenFile, readHiddenFile }) => {
  createHiddenFile({
    name: 'foo.ts',
    content: `export default {}`
  })

  const myHiddenFile = await readHiddenFile('foo.ts')
}

These would then save at ${ root }/.[integration.name]/foo.ts So right next to the hidden .astro folder. And it can't read/write outside that folder.

For context, the usecase is:

For my themes, I'm planning on shipping encrypted versions of my component files so that then they can be decrypted on the user's machine if they have the correct permissions with their env variables. So they'll set an env key, it'll check the api for their "level" and then decrypt the components for that level.

But I don't want it to have to make an api call each time they run or build their project. So once it's done one call and gotten the decryption keys I want to store them on the user's machine. Then they can still develop and reinstall and everything without the api.

I realise I could do this relatively easily without a utility. But I'm going to implement this either way, so just wondered if other people thought there'd be any interest in making it an AIK util.

Easter egg: all-in!

If one integration uses all the utilities from the kit show a log " is all-in. Forever remembered!"

Depends on #31

Has integration check integration position

Just like this kit provides hasIntegration to check if an integration was already included, it could provide a hasPreviousIntegration/hasFollowingIntegration for integrations that interact with others in specific orders (mostly related to markdown and MDX).

This would allow the integration to issue a warning or an error if an integration was added in the incorrect order.

Allow plugins to use several hooks

It's a quite common use-case to need data from a hook into a hook used later on (eg. config from astro:config:done inside astro:build:done). Right now, plugins are bound to a single hook. There may be a way to achieve that, here is an idea of API:

definePlugin({
	setup({ name }) {
		let config

		return {
			"astro:config:setup": ({ config: _config }) => {
				config = _config
			},
			"astro:build:done": () => {
				// do something with config
			}
		}
	}
})

I'm unsure how the API should look like regarding adding utilities to hooks tho 🤔. Isn't it a better fit for an integration at this point?

file factory (name pending) util and unindent util

Just started using this to create virtual modules and dts files. This is just an idea, but would make it easier.

// file-factory.ts
import { unindent } from './unindent'

export const fileFactory = () => {
	let file = ``

	return {
		addLines(lines: string) {
			file += unindent`${ lines }`
		},
		text() {
			return file
		}
	}
}
// unindent-ts
export function unindent(strings, ...values) {
    const result = [];
    const template = strings.reduce((prev, current) => prev + values.shift() + current);

    // Find the common indentation
    const indentMatch = template.match(/^\n?(\s*)/);
    const commonIndent = indentMatch ? indentMatch[1].length : 0;

    // Remove common indentation from each line
    const lines = template.split('\n');
    for (let line of lines) {
        result.push(line.slice(commonIndent));
    }

    // Join the lines back together
    return result.join('\n');
}

Basically means you can create virtual modules and dts files much nicer:

"astro:setup:config": () => {
  const virtualModule = fileFactory()

  virtualModule.addLines(`
    export default ${ JSON.stringify({}) }
  `)
}

outputs

export default {}

all nicely formatted n stuff so you don't have to worry about indents and messy af dts files if you're trying to dynamically generate

Support new "astro:db:setup" hook

Since they added new support for Astro DB the hooks changed. would be nice to get a patch that

  1. Updates the already existing AIK Extended hooks to use the new Astro v4.5 Hooks
    2. adds support to tie into @astrojs/db's new hooks

Expected `name` field on `addVirtualImports`

The latest version expects a name property when creating virtual imports with addVirtualImports(). This is undocumented, and doesn't make much sense given the imports object is used to define virtual module names.

image

Would share a stackblitz, but the TS language server seemed to keep crashing as I tried to repro 😄

[utility] useHookParams

I wonder if can add a bit of magic using https://github.com/unjs/unctx, basically a wrapper that puts all those arguments in a context so that inside a utility we can just call

const { command } = useHookParams("astro:config:setup")

and that would even allow us to automatically expose args from previous hooks instead of having a let config: AstroConfig inside the function body

React typing required for type validation even when not used

The barrel export as astro-integration-kit/utilities causes types for all utilities to be loaded, which requires all optional dependencies to be present, even if unused.

> @inox-tools/[email protected] validate /Users/lotus/IsoWorkspaces/OSS/inox-tools/packages/aik-route-config
> tsc

../../node_modules/.pnpm/[email protected][email protected]/node_modules/astro-integration-kit/src/utilities/add-devtoolbar-framework-app.ts:87:10 - error TS2307: Cannot find module '@vitejs/plugin-react' or its corresponding type declarations.

87   import("@vitejs/plugin-react").then((react) => {
            ~~~~~~~~~~~~~~~~~~~~~~


Found 1 error in ../../node_modules/.pnpm/[email protected][email protected]/node_modules/astro-integration-kit/src/utilities/add-devtoolbar-framework-app.ts:87

 ELIFECYCLE  Command failed with exit code 2.

The solution for this is to include a module declaration in the file to prevent the module typing from depending on the presence of the dependency.

Since modules are merged like interfaces, the module declaration can declare a simple export without details.

Options setup type is incorrect

The type for the setup function is declared as receiving TOptions:

But what it receives is TOptions['options']:

const options = defu(
_options ?? {},
optionsDef?.defaults ?? {},
) as TOptions["options"];

const providedHooks = setup({ name, options });

TS Doesn't complain about it because since the values are covariant

defineIntegration.options should be optional

At the moment you have to pass parameters when using an integration created with defineIntegration because options isn't optional.

So we want to be able to do this:

integrations: [
  myIntegration(),
],

but at the moment have to do this:

integrations: [
  myIntegration({}),
],

defineIntegrations defaults is required when there are no options

import { createResolver, defineIntegration } from 'astro-integration-kit';

export default defineIntegration({
  name: 'my-integration',
  defaults: {} as any as never,
  setup() {
    const { resolve } = createResolver(import.meta.url);

    return {
      'astro:config:setup': async ({ addDevToolbarApp }) => {
        addDevToolbarApp(resolve('./plugin.ts'));
      },
    };
  },
});

Here we should be able not to specify defaults

Plugins: allow using other plugins

A plugin may define a dependency on another plugin, an idea of API:

import { otherPlugin } from "./other-plugin.js"

export const dependentPlugin = definePlugin({
	name: "foo",
	hook: "astro:config:setup",
	dependsOn: [otherPlugin],
	implementation: ({ otherPluginName }) => () => {}
})

"Why AIK" section

In can be confusing for people to understand what's point of AIK, like you don't technically need it to build an Astro + it's not official. A new page at /getting-started/why/ would help!

Automate `pnpm lint:fix`

Right now it's not a great contribution experience to require contributors (especially first time ones) to run pnpm lint:fix. It would be great to have an action that runs on main and does this. I recommend we use autofix-ci for this (I think an example can be found on nuxt repo)

TS quirk for third-party plugins

If you do this:

export const somePlugin = definePlugin();

The inferred type of somePlugin requires importing transitive dependencies to be named (even if it is also your dependency) because it relies on AIK's dependency in Astro.
Because a third-party lib may depend on a different version of Astro, import('astro') would refer to different types depending on where it is. So TS rejects that just for the possibility, even if it is not really the case.

This problem happens for libs that are transpiled and emit a .d.ts. The two solutions are:

  • Set emitDeclarations and declarationsMap to false and publish the source TS files (like AIK does)
  • Explicitly create a named type for the plugin, like so:
    type SomePlugin = Plugin<
    	'utilityName',
    	'astro:config:setup',
    	(p: HookParams) => (params: UtilityParams) => UtilityOutput
    >;
    
    export const somePlugin: SomePlugin = definePlugin();

Codemod API

I was told it's possible to do some black magic here:

Please don't do what I'm about to say, but you can hack around that...
In your postinstall you can check what caused your install by looking at the command that initiated you.
If it was an astro add, daemonize yourself, wait for the command to end and apply that sorting

Adding Astro Qwik to the showcase.

Thought I might as well add it since I'm happily using it in the Qwik integration.

Feel free to copy paste this to save time haha or whatever you prefer.

[Astro Qwik](https://github.com/QwikDev/astro) - by Jack Shelton

JSDoc improvements

Template:

/**
 * This is the main important part, describing the thing below.
 * Often I **only** use this (at least in TS where typing is in code).
 *
 * But the following tags come in handy for me too:
 *
 * @param name Description of a function parameter — even with types provided by TypeScript, sometimes it’s handy to provide extra context/description. I don’t use it all the time though.
 *
 * @see Handy for linking to another bit of code or docs sometimes (although you can also do that in the main description probably).
 *
 * @example
 * // For more complex functions I might show some example usage
 * codeInUse()
 *
 * @deprecated Handy because editors will give some nice visual feedback with strikethrough and there’s a chance to give users some guidance on what to do instead.
 */

Thanks @delucis 🙏

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.