alephjs / aleph.js

The Full-stack Framework in Deno.
https://aleph.deno.dev/
MIT License
5.27k stars 166 forks source link

SWC Macro #78

Open shadowtime2000 opened 3 years ago

shadowtime2000 commented 3 years ago

A plugin to replace .env variables in a certain manner. Initially proposed in #77. Initial design used regex to replace anything surrounded by handlebars. I think we should use deno_swc which will allow us to instead replace Deno.env. anything. We could possibly look into requiring ALEPH_PUBLIC_ prefix to .env variables unless it is accessed inside a useDeno hook.

shadowtime2000 commented 3 years ago

@ije Thoughts? @alfredosalzillo Are you still interested in creating such an env plugin?

ije commented 3 years ago

maybe too much to import the deno_swc for the env plugin, 0.3 will include a new compiler using swc i can implement this function without plugin imported.

shadowtime2000 commented 3 years ago

@ije Makes sense!

ije commented 3 years ago

i perfer a new concept swc-marco can be a solution:

import env from 'https://deno.land/x/aleph/swc-macros/env.macro.ts'

const value = env('KEY')

it will be transpiled to below code:

const value = __ALEPH_ENV.get('KEY')

and the macro will export the deno.env as __ALEPH_ENV.

what do you think? @shadowtime2000 @alfredosalzillo

ije commented 3 years ago

with that, people can write their own macro that gives more power to define your code syntax.

alfredosalzillo commented 3 years ago

I agree. I prefer this solution too.

ije commented 3 years ago

for example, we can transform graphql string to AST at build time with macro:

import gql from 'https://deno.land/x/aleph/macros/graphql.macro.ts'

const query = gql`
  {
    user(id: 123) {
      firstName
      lastName
    }
  }
`

output code:

const query = {
  "kind": "Document",
  "definitions": [ ... ]
}
shadowtime2000 commented 3 years ago

I like the idea of an SWC macro, it could possibly then help us with #60.

shadowtime2000 commented 3 years ago

@ije How exactly would this be written? Will we write it within the new compiler after it is merged or will we another repo for this project or something? I think SWC macros could be useful just all around in a ton of places.

ije commented 3 years ago

it seems like:

// https://deno.land/x/aleph/swc-macros/env.macro.ts

export default function EnvMacro(key: string): string {
  return ''
}

EnvMacro.macro = {
  // inject code to `main.js` at ssr/ssg
  inject(): string {
    return `window.__ALEPH_ENV=${JSON.stringify(Deno.env)}`
  },
  // transform macro call expression
  transform(arg0): string {
    return `__ALEPH_ENV.get(${arg0})`
  }
}
shadowtime2000 commented 3 years ago

@ije Thx, but I was actually asking about how the compiler which expands the macros will be organized. I don't think we should have an inject method which injects that into the main file, I think it would be better if we just did something like this:

export default function EnvMacro(key: string): string {
  return ''
}

EnvMacro.macro = {
    transform(arg0): string {
        return Deno.env.get(arg0);
    }
}
ije commented 3 years ago

@shadowtime2000 the transform should return a js code fragment that why i added the inject method(it's optional) to inject deno runtime variables. i will add the feature in the new compiler, no extra dependency needed.

shadowtime2000 commented 3 years ago

Tbh, I feel like macros purely for a framework like this is a little overkill and we could look into creating a library for these macros that doesn't require Aleph to be used.

shadowtime2000 commented 3 years ago

@ije I don't think it is a good idea to dump everything in Deno.env into a global namespace because there could be unused .env variables for stuff like API keys which could be used in the /api/ routes, which makes that a security concern. I think this should be good enough:

export default function EnvMacro(key: string): string {
  return ''
}

EnvMacro.macro = {
    transform(arg0): string {
        return `"${Deno.env.get(arg0)}"`;
    }
}

So env("foo") will be replaced with "bar".

ije commented 3 years ago

@shadowtime2000 you are right it's a bad idea to inject deno.env!

ije commented 3 years ago

i feel that the maco function is very easy to implement in the new compile with swc, if there is a statement like import macroFn from "./xxx.macro.ts", the macroFn will be treated as a macro. if we decide to implement it in a library then we need an ast compiler that is heavy.

shadowtime2000 commented 3 years ago

@ije Good point, it would be easier to make it a library once there is a more standard form for ast modification and compilation and stuff.

ije commented 3 years ago

@shadowtime2000 for sure

shadowtime2000 commented 3 years ago

We should probably allow returning an AST or something for more organized complex macros.

shadowtime2000 commented 3 years ago

I think we should maybe instead just invoke a macro if macro data is present on the function.