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

Rewrite in TypeScript #20

Closed
wants to merge 19 commits into from

Conversation

JunichiSugiura
Copy link

#18

@jescalan It seems like TypeScript doesn't currently support subpaths exports as described here and here.

One solution is to export everything from index.ts. However it'll introduce breaking changes since every consumer has to change the way to import.

// currently
import hydrate from 'next-mdx-remote/hydrate'
import renderToString from 'next-mdx-remote/render-to-string'

// if we export all from `index.ts`
import {  hydrate, renderToString } from 'next-mdx-remote'

This is not a big library so the change above is acceptable I think but it's up to how you feel about the api change.
Let me know what you think.

@hashicorp-cla
Copy link

hashicorp-cla commented Jul 26, 2020

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

@jescalan jescalan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checked whether the client-side code removal will still work properly when a getServerProps only and a client-side import both come from the same statement and it seems like it does, so I think we can shift the API towards what you suggested 🎉

package.json Outdated
@@ -48,14 +52,19 @@
"next.js"
],
"license": "MPL-2.0",
"main": "index.js",
"exports": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only supported by node v13 and above if I'm not mistaken, which means we'd be removing LTS node support from this library. Is there any way we can get around this?

src/types.ts Outdated

// export interface Components {
// [key: string]: React.Component<any>
// }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔪?

@JunichiSugiura
Copy link
Author

Sounds great! Let me find a time to work on it tomorrow.

@jescalan
Copy link
Contributor

Ok I have received another update that it's "not recommended", and should be tested to make sure it works haha

@JunichiSugiura
Copy link
Author

Sorry, it's been a crazy week for me. I'll reschedule it on Saturday.

@JunichiSugiura
Copy link
Author

Hmm, I've tested with re-exporting both renderToString and hydrate from index.tsx but it throw "fs" module not found error on the next app side. Which indicates tree shaking doesn't work and renderToString is still included inside client side code. I've also tested with next@9.5 (webpack5 beta enabled) but no luck.

@JunichiSugiura
Copy link
Author

I found out if I respect current file structure (i.e. hydrate.ts instead of src/hydrate.ts), TS resolves submodules on the app site. I'll remove src/ and dist/.

@JunichiSugiura JunichiSugiura changed the title [WIP] Rewrite in TypeScript Rewrite in TypeScript Aug 1, 2020
@JunichiSugiura
Copy link
Author

@jescalan It should do the trick now.

Copy link
Contributor

@jescalan jescalan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is really great. Thanks so much for all the work you put into this! I'm very impressed by the cleanliness of the results. Just had a couple questions as I am not a true typescript pro yet over here.

@@ -5,7 +5,7 @@ const puppeteer = require('puppeteer')
const handler = require('serve-handler')
const http = require('http')
const rmfr = require('rmfr')
const renderToString = require('../render-to-string')
const renderToString = require('../render-to-string').default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary now?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary now?

CommonJS (Node's require() and exports) is not compatible with ES6 default exports. But in this case as we are talking about puppeteer tests I don't see a reason. We are not using TS here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CommonJS (Node's require() and exports) is not compatible with ES6 default exports

Yes, that's the reason. Without it'll throw TypeError: renderToString is not a function

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also convert all the test files to TS but I don't have enough time for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean if someone is not using typescript, they will need to pull default in order for the library to work? This seems like a pretty negative change if so, given that the majority of users are likely not on typescript...

path.remove()
},
// the `makeShortcode` template is nice for error handling but we
// don't need it here as we are manually injecting dependencies
VariableDeclaration(path) {
VariableDeclaration: function (path) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason for these additions?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason for these additions?

I don't see a reason for these changes.

package.json Outdated Show resolved Hide resolved
import presetReact from '@babel/preset-react'
import { renderToString as reactRenderToString } from 'react-dom/server'
import React from 'react'
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, why ignore this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the babel plugin module is written in JS and we don't have type definition for it, tsc complains.
I'm not sure where to find type definitions for babel plugins. Maybe someone can help.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I provided babel-plugin-mdx-browser.d.ts: 1341796


if (!now || !later || !later.code) {
throw new Error('Failed to transform mdx source code')
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem like a super useful error message - do you have any more context on when you encountered this and what caused it? Maybe we can add more detail to the error?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type of transformAsync is Promise<BabelFileResult | null> and we need to handle the null case. Which is unlikely to happen since it only depends on babel plugins and code const which is returned by mdx(...).

types.ts Outdated

export interface Scope {}

export type Components = Parameters<typeof createElement>[1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is some crazy wizardry here ✨ - could you help me to understand what's going on? afaik, the Parameters utility creates a type out of the arguments to a function, but you're passing in the results of a typeof operation which I'd think would return "function"?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jescalan No, the typeof here means the types of the parameters.

For example:

declare function f1(arg: { a: number; b: string }): void;

type T3 = Parameters<typeof f1>;
//    ^ = type T3 = [arg: {
    a: number;
    b: string;
}]

@jescalan
Copy link
Contributor

Just pulled this down to run tests and see if we could get it live - both mdx and babel-preset-react do not have typescript types, and types are not present in the library or definitely-typed for either one. tsc errors on npm test due to implicitAny being set to false.

I tinkered for a bit with trying to get types in for these libraries but ultimately moved on, its not worth the effort for me right now. Let me know if you saw this during your own local dev and how you might want to handle it!

@brianespinosa
Copy link
Contributor

Well... @JunichiSugiura you went above and beyond on what I did in my PR. I guess I should have looked to see if any PRs were open doing something similar. 👍🏽 This PR would resolve #24 and then some.

@jescalan let me know if I should decline #26 and instead submit a separate PR for #25

@theprobugmaker
Copy link

@jescalan I answered a few questions you had on his code.

@JunichiSugiura
Copy link
Author

I'm sorry it's been a crazy few weeks for me. Let me get back to you tomorrow.

@miku86
Copy link

miku86 commented Sep 12, 2020

I'm sorry it's been a crazy few weeks for me. Let me get back to you tomorrow.

Hello Junichi,

thanks for your work so far.

Any help required to finish this?

@JunichiSugiura
Copy link
Author

JunichiSugiura commented Sep 13, 2020

tsc errors on npm test due to implicitAny being set to false

It's due to @types/ which I had locally wasn't committed. I stupidly run git clean -xdf to reproduce your error and now all the definition files inside the dir are gone🤦‍♂️

I'll recreate these files.

@JunichiSugiura
Copy link
Author

Sorry for taking it so long. I finally managed to find some time to

  • reflect some reviews
  • fix third-party related type errors
  • merge master

Hope it works this time🤞

Copy link
Contributor

@jescalan jescalan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again for the great work here @JunichiSugiura! We're getting super close I think

@@ -5,7 +5,7 @@ const puppeteer = require('puppeteer')
const handler = require('serve-handler')
const http = require('http')
const rmfr = require('rmfr')
const renderToString = require('../render-to-string')
const renderToString = require('../render-to-string').default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean if someone is not using typescript, they will need to pull default in order for the library to work? This seems like a pretty negative change if so, given that the majority of users are likely not on typescript...

return {
visitor: {
// remove all imports, we will add these to scope manually
ImportDeclaration(path) {
ImportDeclaration(path: any) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does babel not have a type for this one?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the types I got working (explanation in the commit):
06kellyjac@d5910b0

I couldn't really find any docs for writing babel plugins in typescript 🤷 so I had to dive through the definitions.
Also it's probably worth double checking the Optional Chaining logic matches before. + that the code removed was actually incorrect.

The tests ran successfully.

@jescalan
Copy link
Contributor

I'm going to close this one due to inactivity, and because we have typings shipping out shortly

@jescalan jescalan closed this Dec 23, 2020
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

Successfully merging this pull request may close these issues.

7 participants