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

yarn react build|dev #195

Merged
merged 25 commits into from
Aug 20, 2021
Merged

yarn react build|dev #195

merged 25 commits into from
Aug 20, 2021

Conversation

ericclemmons
Copy link
Contributor

@ericclemmons ericclemmons commented Aug 18, 2021

  • Replace Nx #177
  • Replace microbundle #186
  • Use tsup for bundling – https://tsup.egoist.sh/
  • Output @aws-amplify/ui-react/styles.css
  • Inline all @aws-amplify/* dependencies (so it's a single bundle)
  • Remove Next.s compilation for packages/*
  • yarn react dev for development
  • yarn react build for production build
  • yarn core build
  • Watch changes in @aws-amplify/ui-core when doing yarn react dev
❯ yarn react dev
yarn run v1.22.10
$ yarn workspace @aws-amplify/ui-react dev
$ rimraf dist
$ tsup --watch src --watch ../core/src
 CLI  Building entry: src/index.tsx
 CLI  Using tsconfig: /Users/ecclemm/Projects/aws-amplify/amplify-ui/packages/react/tsconfig.json
 CLI  tsup v4.14.0
 CLI  Using tsup config: /Users/ecclemm/Projects/aws-amplify/amplify-ui/packages/react/tsup.config.cjs
 CLI  Running in watch mode
 CLI  Target: node12
 CJS  Build start
 ESM  Build start
 ESM  Build success in 6788ms
 CJS  Build success in 7019ms
 CLI  Watching for changes in "src" | "../core/src"
 CLI  Ignoring changes in "**/{.git,node_modules}/**" | "dist"
 DTS  Build start
 DTS  Build success in 28272ms
 CLI  Change detected: change ../core/src/authService.ts
 CJS  Build start
 ESM  Build start
 CJS  Build success in 1408ms
 ESM  Build success in 1407ms

"module": "dist/index.js",
"exports": {
".": "./dist/index.js",
"./styles.css": "./dist/index.css"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

import "@aws-amplify/ui-react/styles.css" correctly resolves to dist/index.css.

Neat, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

neat

Comment on lines 49 to 50
"@aws-amplify/ui-core": "^0.0.1",
"@aws-amplify/ui-theme-base": "^0.0.1",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Build tools like microbundle, tsup, etc. externalize dependencies and inline devDependencies.

This is helpful for using packages that we don't want to publish.

Copy link
Contributor

Choose a reason for hiding this comment

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

Broader question: do we want to publish ui-theme-base? I noticed we publish @aws-amplify/ui which is kind of similar to what ui-theme-base is now. I don't have a strong opinion, just wanted to bring it up. Should we rename ui-theme-base to just ui?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, any cross-platform/framework dependencies (like the state machine, design tokens, or even specs (we ran into an issue with that!)) ideally lives in @aws-amplify/ui-core.

But you're right to ask about @aws-amplify/ui.

ui-core would be a new package, but I don't think it makes sense to have. ui-core is kinda our equivalent of ui, so you're right – maybe we rename & merge ui-core and theme-base into ui.

The only thing that I found weird is aws-amplify installs it by default:
https://github.com/aws-amplify/amplify-js/blob/da8ef238928fdcad7ab307350ffff8448eec5b26/packages/aws-amplify/package.json#L47

But I have no idea why, or see the need for it.

The more I type it out, the more it makes sense for @aws-amplify/ui to contain our core/shared assets and @aws-amplify/ui-* be framework-specific stuff. core just seemed to be common convention in the ecosystem (e.g. @babel/core).

Let's queue this up for another cleanup task.

jsxFactory: options.jsxFactory,
jsxFragment: options.jsxFragment,
sourcemap: options.sourcemap,
+ inject: ['./src/react-shim.js'],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -1,3 +1,5 @@
import './styles.css';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is really nice – building (via PostCSS) styles as part of a single package & process.

Copy link
Contributor

Choose a reason for hiding this comment

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

Dumb question: if we import the styles here, developers using the React components would no longer need to import the styles like import '@aws-amplify/ui-react/styles.css' anymore? And would developers be able to get un-styled React components?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Somehow the SCSS stuff just worked?? I need to check the docs to be sure...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question @dbanksdesign! No, import '@aws-amplify/ui-react/styles.css' is still required.

What import does here is allow the bundler (tsup, microbundle, whatever) automatically output both JS & CSS with a single process. (Compared to having to watch CSS and JS separately)

This is consistent with how, say, an application is bundled with webpack: even though your app has JS, CSS, SVGs, PNGs, whatever, the bundler identifies all dependencies and outputs them based on your configuration.

Comment on lines -25 to -29
},
"dependencies": {
"@fontsource/inter": "^4.5.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The bundler had issues with WOFF files inside of this dependency.

Admittedly, this is weird to me as part of a library. Because fonts require asset files (e.g. .woff, .ttf, etc.), these have to be bundled by the client app.

Normally, I see styles only specify font-family and leave it to the consumer to determine where the fonts are located:

Because fonts can be very expensive, I think we should revisit #165 and try to make bundle-size as much of an opt-in as possible, like https://tailwindui.com/documentation#optional-add-the-inter-font-family.

If a customer doesn't want it, font-family will naturally go to the next available font.

If a customer wants to load it in a blocking way, they can use <link>.

If a customer wants to load it in a non-blocking way, they can do what Next.js does:

https://nextjs.org/docs/basic-features/font-optimization

@ericclemmons ericclemmons temporarily deployed to ci August 20, 2021 18:32 Inactive
@ericclemmons ericclemmons marked this pull request as ready for review August 20, 2021 18:33
@@ -1,7 +1,7 @@
{
"private": true,
"scripts": {
"install": "yarn run theme-base build:all",
"install": "yarn run theme-base build:all && yarn core build && yarn react build",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Going to replace this with turbo

@@ -37,7 +37,8 @@
},
"dependencies": {
"patch-package": "^6.4.7",
"postinstall-postinstall": "^2.1.0"
"postinstall-postinstall": "^2.1.0",
"tsup": "^4.14.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

tsup checked all the boxes that vite did, + .d.ts output.

Nx requires a ton of convention, which is great, but more than I wanted to change.

microbundle is slow because of rollup.

@@ -21,5 +23,8 @@
"@types/lodash": "^4.14.170",
"@types/webpack-env": "^1.16.2",
"tslib": "^2.3.0"
},
"peerDependencies": {
"aws-amplify": "3.x.x || 4.x.x"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Otherwise our amazon-cognito-identity-js and aws-amplify dependencies get bundled!

@@ -21,15 +28,18 @@
"test:unit:watch": "jest --watch"
},
"dependencies": {
"@aws-amplify/ui-core": "^0.0.1",
"@aws-amplify/ui-theme-base": "^0.0.1",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll move theme-base into core in another PR. We won't lose tree-shaking or anything, but it'll be 1 less bundle for customers to keep in sync.

Comment on lines +40 to +42
"aws-amplify": "3.x.x || 4.x.x",
"react": ">= 16.8.0",
"react-dom": ">= 16.8.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This way we don't bundle dependencies.

Comment on lines +9 to +10
import * as React from 'react';
export { React };
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Vite does this automatically. I had to patch tsup to avoid changing EVERY .tsx file.

Comment on lines +3 to +4
"moduleResolution": "node",
"baseUrl": ".",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought this was the default, but tsup & vite weren't picking up on node_modules until I added this.

Copy link
Contributor

@dbanksdesign dbanksdesign left a comment

Choose a reason for hiding this comment

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

Overall, I love it. A couple small questions, nothing blocking.

@@ -9,10 +9,10 @@ const withNextPluginPreval = require('next-plugin-preval/config')();
const withCompileNodeModules = require('@moxy/next-compile-node-modules')({
include: [
// Using `path.dirname` because `package.json#main` doesn't exist in some packages yet
path.dirname(require.resolve('@aws-amplify/ui-core/package.json')),
Copy link
Contributor

Choose a reason for hiding this comment

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

ahhh so nice

@@ -1,10 +1,4 @@
// TODO Remove this once @aws-amplify/ui-react is compiled
Copy link
Contributor

Choose a reason for hiding this comment

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

huzzah

Copy link
Contributor

Choose a reason for hiding this comment

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

Removing TODOs feels great!

@@ -1,3 +1,5 @@
import './styles.css';
Copy link
Contributor

Choose a reason for hiding this comment

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

Dumb question: if we import the styles here, developers using the React components would no longer need to import the styles like import '@aws-amplify/ui-react/styles.css' anymore? And would developers be able to get un-styled React components?

@@ -1,7 +1,7 @@
{
"private": true,
"scripts": {
"install": "yarn run theme-base build:all",
"install": "yarn run theme-base build:all && yarn core build && yarn react build",
Copy link
Contributor

Choose a reason for hiding this comment

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

ohh I like, now I can just run install and then start up the docs or example next server

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly right @dbanksdesign – I want the majority of the packages/examples/docs/etc. to "just work" with git clone and yarn install.

The only exception is really environments/, and that's because they require an AWS account.

In the future, we can even avoid that by including aws-exports.js – we would only need to monitor those resources for usage/abuse.

"declaration": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"rootDir": "./src",
"outDir": "./dist",
"skipLibCheck": true,
"sourceMap": true,
"module": "commonjs",
"target": "es5"
"module": "esnext",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, TIL : https://stackoverflow.com/questions/41993811/understanding-target-and-module-in-tsconfig

module basically means module.exports or import/export or import():

microsoft/TypeScript#24082

"module": "commonjs",
"target": "es5"
"module": "esnext",
"target": "es2015"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

target means the language features:

https://stackoverflow.com/questions/41993811/understanding-target-and-module-in-tsconfig

Targeting evergreen browsers, this could even be esnext but I figure we'll standup more examples (CRA, Nuxt, etc.) to determine what that impact is.

But the less TS has to transpile, the faster our builds will be.

/**
* @type {import("tsup").Options}
*/
module.exports = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did it this way for type safety vs. tsup src/index.tsx --format cjs,esm ...

jsxFactory: options.jsxFactory,
jsxFragment: options.jsxFragment,
sourcemap: options.sourcemap,
+ inject: ['./src/globals.js'],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@wlee221 wlee221 left a comment

Choose a reason for hiding this comment

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

This is looking great! Thanks @ericclemmons. Just got some suggestions/questions.

## Next/React Development
## `@aws-amplify/core`

- `yarn core build` to rebuild for production.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we mention yarn core build --watch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yarn core dev is the answer for local development (including watching).

(I also learned that the build tool may not always be the dev tool!)

@@ -1,10 +1,4 @@
// TODO Remove this once @aws-amplify/ui-react is compiled
Copy link
Contributor

Choose a reason for hiding this comment

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

Removing TODOs feels great!

],
"scripts": {
"build": "tsc",
"prebuild": "rimraf dist",
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we have a separate yarn clean script here? I find explicit clean scripts when I'm looking at module/build issues.

Suggested change
"prebuild": "rimraf dist",
"clean": "rimraf dist",
"prebuild": "yarn clean",

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You know, I went back-and-forth on this. What I noticed was that it was tough to trace when something was being used and where. (build:icons is an example of this)

Having clean explicitly defined kinda felt like I was promoting it to a public API (e.g. yarn react clean) vs. having only build|dev being the public APIs.

I hope the indirection from build => prebuild => clean is clearer with build => prebuild 🙏

(I don't have a strong opinion – I've done NPM scripts every which way since per-env)

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a use-case to run only a clean? I've realized whenever I'm doing a clean it's because I want to blow up the build artifacts and rebuild them, so just being part of prebuild makes sense to me. But if there are use cases for "clean and not build" I'm for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great question. I don't have one. Your use-case models my experience as well:

  • "Build for production", which means a clean slate so we don't re-publish old artifacts.
  • "Dev" should not remove clean because I found out it breaks hot-reload when those references disappear.

I suppose there could be a reason to clean and do dev, but IME yarn install is basically our starting point for "setup and build everything, and I'll chose what part I'm working on".

@@ -0,0 +1,12 @@
diff --git a/node_modules/tsup/dist/index.js b/node_modules/tsup/dist/index.js
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@ericclemmons ericclemmons left a comment

Choose a reason for hiding this comment

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

Responding to comments, but somehow it's a review? ¯_(ツ)_/¯

Comment on lines -6 to -7
@import '~@fontsource/inter/index.css';
@import '~@fontsource/inter/variable.css';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh yeah, with this change we will need to update our theme instructions to add the Inter font (see above comment)

## Next/React Development
## `@aws-amplify/core`

- `yarn core build` to rebuild for production.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

yarn core dev is the answer for local development (including watching).

(I also learned that the build tool may not always be the dev tool!)

@@ -1,7 +1,7 @@
{
"private": true,
"scripts": {
"install": "yarn run theme-base build:all",
"install": "yarn run theme-base build:all && yarn core build && yarn react build",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly right @dbanksdesign – I want the majority of the packages/examples/docs/etc. to "just work" with git clone and yarn install.

The only exception is really environments/, and that's because they require an AWS account.

In the future, we can even avoid that by including aws-exports.js – we would only need to monitor those resources for usage/abuse.

],
"scripts": {
"build": "tsc",
"prebuild": "rimraf dist",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

You know, I went back-and-forth on this. What I noticed was that it was tough to trace when something was being used and where. (build:icons is an example of this)

Having clean explicitly defined kinda felt like I was promoting it to a public API (e.g. yarn react clean) vs. having only build|dev being the public APIs.

I hope the indirection from build => prebuild => clean is clearer with build => prebuild 🙏

(I don't have a strong opinion – I've done NPM scripts every which way since per-env)

@@ -1,3 +1,5 @@
import './styles.css';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question @dbanksdesign! No, import '@aws-amplify/ui-react/styles.css' is still required.

What import does here is allow the bundler (tsup, microbundle, whatever) automatically output both JS & CSS with a single process. (Compared to having to watch CSS and JS separately)

This is consistent with how, say, an application is bundled with webpack: even though your app has JS, CSS, SVGs, PNGs, whatever, the bundler identifies all dependencies and outputs them based on your configuration.

@ericclemmons ericclemmons temporarily deployed to ci August 20, 2021 20:53 Inactive
@ericclemmons ericclemmons temporarily deployed to ci August 20, 2021 21:36 Inactive
@ericclemmons ericclemmons temporarily deployed to ci August 20, 2021 21:36 Inactive
@ericclemmons ericclemmons merged commit 6970069 into main Aug 20, 2021
@ericclemmons ericclemmons deleted the tsup branch November 30, 2021 19:37
thaddmt pushed a commit that referenced this pull request Apr 7, 2023
Sync amplify-ui to amplify-ui-staging
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.

3 participants