Coder Social home page Coder Social logo

florian-lefebvre / astro-integration-kit Goto Github PK

View Code? Open in Web Editor NEW
40.0 5.0 8.0 752 KB

A package that contains utilities to help you build Astro integrations.

Home Page: https://astro-integration-kit.netlify.app

License: MIT License

TypeScript 85.49% JavaScript 3.65% Astro 10.86%
astro utilities utils withastro

astro-integration-kit's Introduction

astro-integration-kit

A package that contains utilities to help you build Astro integrations.

To see how to get started, check out the package README

Licensing

MIT Licensed. Made with ❤️ by Florian Lefebvre.

astro-integration-kit's People

Contributors

adammatthiesen avatar brycerussell avatar florian-lefebvre avatar fryuni avatar jdtjenkins avatar ktym4a avatar lilnasy avatar namchee 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  avatar  avatar

Watchers

 avatar  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.

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

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

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

"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!

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 }) => () => {}
})

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

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)

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.

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();

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.

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?

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 🙏

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({}),
],

[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

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

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

Typing for AstroDB after semver 0.9 seems to have broken

Console error presented about deps:

└─┬ astro-integration-kit 0.12.0
  └── ✕ unmet peer @astrojs/db@^0.9.0: found 0.10.6

the only side effect of this seems to be lost typing for the extendDb hook within the main astro integration file.
image

If i revert the Astrojs/db package to a 0.9... version the typing returns.

The broken typing does not appear to effect the actual functionality of the integration as everything else appears to be still functioning as intended

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

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 😄

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.