Skip to content

Commit

Permalink
Support defining the app in TypeScript (TS SDK) (#2335)
Browse files Browse the repository at this point in the history
Implement the TS SDK as a preview feature.
  • Loading branch information
sodic authored Oct 10, 2024
1 parent 8207e6d commit e92cb25
Show file tree
Hide file tree
Showing 51 changed files with 3,475 additions and 164 deletions.
71 changes: 67 additions & 4 deletions waspc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,77 @@

## 0.15.0

### 🎉 New Features
### 🎉 New Features and improvements

- Upgrade to the latest Prisma version which makes Wasp faster!
- Upgrade to the latest React Router version which sets us up for some cool new features in the future.
#### Write your app config in TypeScript (preview feature)

Wasp 0.15.0 ships a preview feature that lets you define your app using TypeScript instead of the Wasp language.

So, instead of this:

```c
app TodoApp {
wasp: {
version: "^0.15.0"
},
title: "TodoApp",
auth: {
userEntity: User,
methods: {
usernameAndPassword: {}
},
onAuthFailedRedirectTo: "/login"
}
}

route RootRoute { path: "/", to: MainPage }
page MainPage {
authRequired: true,
component: import { MainPage } from "@src/MainPage"
}
```

You can now write this:

```typescript

improt { App } from 'wasp-config'

const app = new App('TodoApp', {
title: 'TodoApp',
wasp: {
version: '^0.15.0',
},
})

app.auth({
userEntity: 'User',
methods: {
usernameAndPassword: {}
},
onAuthFailedRedirectTo: '/login',
})

const mainPage = app.page('MainPage', {
authRequired: true,
component: { import: 'MainPage', from: '@src/MainPage' },
})

app.route('RootRoute', {
path: '/',
to: mainPage,
})
```

To learn more about this feature and how to activate it, check out the docs.

### ⚠️ Breaking Changes

There are some breaking changes with React Router 6 which will require you to update your code.
Also, the new version of Prisma may cause breaking changes depending on how you're using it.


Read more about them in the migration guide: https://wasp-lang.dev/docs/migration-guides/migrate-from-0-14-to-0-15
Read more about breaking changes in the migration guide: https://wasp-lang.dev/docs/migration-guides/migrate-from-0-14-to-0-15

### 🐞 Bug fixes

Expand All @@ -20,6 +81,8 @@ Read more about them in the migration guide: https://wasp-lang.dev/docs/migratio

### 🔧 Small improvements

- Upgrade to the latest Prisma version which makes Wasp faster!
- Upgrade to the latest React Router version which sets us up for some cool new features in the future.
- Enable users to use Mailgun's EU region by setting the `MAILGUN_API_URL` env variable.
- Validate `userEntity` ID field's `@default` attribute.

Expand Down
5 changes: 4 additions & 1 deletion waspc/cli/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import qualified Wasp.Cli.Command.Start.Db as Command.Start.Db
import Wasp.Cli.Command.Studio (studio)
import qualified Wasp.Cli.Command.Telemetry as Telemetry
import Wasp.Cli.Command.Test (test)
import Wasp.Cli.Command.TsConfigSetup (tsConfigSetup)
import Wasp.Cli.Command.Uninstall (uninstall)
import Wasp.Cli.Command.WaspLS (runWaspLS)
import Wasp.Cli.Message (cliSendMessage)
Expand All @@ -51,6 +52,7 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
["start"] -> Command.Call.Start
["start", "db"] -> Command.Call.StartDb
["clean"] -> Command.Call.Clean
["ts-setup"] -> Command.Call.TsSetup
["compile"] -> Command.Call.Compile
("db" : dbArgs) -> Command.Call.Db dbArgs
["uninstall"] -> Command.Call.Uninstall
Expand Down Expand Up @@ -102,6 +104,7 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
Command.Call.Start -> runCommand start
Command.Call.StartDb -> runCommand Command.Start.Db.start
Command.Call.Clean -> runCommand clean
Command.Call.TsSetup -> runCommand tsConfigSetup
Command.Call.Compile -> runCommand compile
Command.Call.Db dbArgs -> dbCli dbArgs
Command.Call.Version -> printVersion
Expand Down Expand Up @@ -130,7 +133,7 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do

handleInternalErrors :: E.ErrorCall -> IO ()
handleInternalErrors e = do
putStrLn $ "\nInternal Wasp error (bug in compiler):\n" ++ indent 2 (show e)
putStrLn $ "\nInternal Wasp error (bug in the compiler):\n" ++ indent 2 (show e)
exitFailure

-- | Sets env variables that are visible to the commands run by the CLI.
Expand Down
1 change: 1 addition & 0 deletions waspc/cli/src/Wasp/Cli/Command/Call.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ data Call
| StartDb
| Clean
| Uninstall
| TsSetup
| Compile
| Db Arguments -- db args
| Build
Expand Down
2 changes: 1 addition & 1 deletion waspc/cli/src/Wasp/Cli/Command/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ module Wasp.Cli.Command.Common
)
where

import Control.Monad.Except
import qualified Control.Monad.Except as E
import Control.Monad.IO.Class (liftIO)
import StrongPath (Abs, Dir, Path')
import qualified StrongPath as SP
import StrongPath.Operations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import qualified Data.Text as T
import StrongPath (Abs, Dir, File, Path')
import Wasp.Cli.Command.CreateNewProject.Common (defaultWaspVersionBounds)
import Wasp.Cli.Command.CreateNewProject.ProjectDescription (NewProjectAppName, NewProjectName)
import Wasp.Project.Analyze (findWaspFile)
import Wasp.NodePackageFFI (InstallablePackage (WaspConfigPackage), getPackageInstallationPath)
import Wasp.Project.Analyze (WaspFilePath (..), findWaspFile)
import Wasp.Project.Common (WaspProjectDir)
import Wasp.Project.ExternalConfig.PackageJson (findPackageJsonFile)
import qualified Wasp.Util.IO as IOUtil
Expand All @@ -26,8 +27,11 @@ replaceTemplatePlaceholdersInWaspFile ::
NewProjectAppName -> NewProjectName -> Path' Abs (Dir WaspProjectDir) -> IO ()
replaceTemplatePlaceholdersInWaspFile appName projectName projectDir =
findWaspFile projectDir >>= \case
Nothing -> return ()
Just absMainWaspFile -> replaceTemplatePlaceholdersInFileOnDisk appName projectName absMainWaspFile
Left _error -> return ()
Right (WaspLang absMainWaspFile) -> replaceTemplatePlaceholders absMainWaspFile
Right (WaspTs absMainTsFile) -> replaceTemplatePlaceholders absMainTsFile
where
replaceTemplatePlaceholders = replaceTemplatePlaceholdersInFileOnDisk appName projectName

-- | Template file for package.json file has placeholders in it that we want to replace
-- in the package.json file we have written to the disk.
Expand All @@ -40,8 +44,16 @@ replaceTemplatePlaceholdersInPackageJsonFile appName projectName projectDir =
Just absPackageJsonFile -> replaceTemplatePlaceholdersInFileOnDisk appName projectName absPackageJsonFile

replaceTemplatePlaceholdersInFileOnDisk :: NewProjectAppName -> NewProjectName -> Path' Abs (File f) -> IO ()
replaceTemplatePlaceholdersInFileOnDisk appName projectName =
updateFileContentWith (replacePlaceholders waspTemplateReplacements)
replaceTemplatePlaceholdersInFileOnDisk appName projectName file = do
waspConfigPackagePath <- getPackageInstallationPath WaspConfigPackage
let waspTemplateReplacements =
[ ("__waspConfigPath__", waspConfigPackagePath),
("__waspAppName__", show appName),
("__waspProjectName__", show projectName),
("__waspVersion__", defaultWaspVersionBounds)
]
-- TODO: We do this in all files, but not all files have all placeholders
updateFileContentWith (replacePlaceholders waspTemplateReplacements) file
where
updateFileContentWith :: (Text -> Text) -> Path' Abs (File f) -> IO ()
updateFileContentWith updateFn absFilePath = IOUtil.readFileStrict absFilePath >>= IOUtil.writeFileFromText absFilePath . updateFn
Expand All @@ -50,9 +62,3 @@ replaceTemplatePlaceholdersInFileOnDisk appName projectName =
replacePlaceholders replacements content = foldl' replacePlaceholder content replacements
where
replacePlaceholder content' (placeholder, value) = T.replace (T.pack placeholder) (T.pack value) content'

waspTemplateReplacements =
[ ("__waspAppName__", show appName),
("__waspProjectName__", show projectName),
("__waspVersion__", defaultWaspVersionBounds)
]
38 changes: 38 additions & 0 deletions waspc/cli/src/Wasp/Cli/Command/TsConfigSetup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Wasp.Cli.Command.TsConfigSetup (tsConfigSetup) where

import Control.Concurrent (Chan, newChan)
import Control.Concurrent.Async (concurrently)
import Control.Monad.Except (throwError)
import Control.Monad.IO.Class (liftIO)
import StrongPath (Abs, Dir, Path')
import System.Exit (ExitCode (..))
import Wasp.Cli.Command (Command, CommandError (..), require)
import Wasp.Cli.Command.Require (InWaspProject (InWaspProject))
import qualified Wasp.Generator.Job as J
import Wasp.Generator.Job.IO (readJobMessagesAndPrintThemPrefixed)
import Wasp.Generator.Job.Process (runNodeCommandAsJob)
import Wasp.NodePackageFFI (InstallablePackage (WaspConfigPackage), getPackageInstallationPath)

-- | Prepares the project for using Wasp's TypeScript SDK.
tsConfigSetup :: Command ()
tsConfigSetup = do
InWaspProject waspProjectDir <- require
messageChan <- liftIO newChan
-- NOTE: We're also installing the user's package.json dependencies here
-- This is to provide proper IDE support for users working with the TS SDK
-- (it needs the `wasp-config` package).
liftIO (installWaspConfigPackage messageChan waspProjectDir)
>>= onLeftThrowError
where
onLeftThrowError = either (throwError . CommandError "npm install failed") pure

installWaspConfigPackage :: Chan J.JobMessage -> Path' Abs (Dir a) -> IO (Either String ())
installWaspConfigPackage chan projectDir = do
installationPath <- getPackageInstallationPath WaspConfigPackage
(_, exitCode) <-
concurrently
(readJobMessagesAndPrintThemPrefixed chan)
(runNodeCommandAsJob projectDir "npm" ["install", "--save-dev", "file:" ++ installationPath] J.Wasp chan)
return $ case exitCode of
ExitSuccess -> Right ()
ExitFailure _ -> Left "Failed to install wasp-config package"
1 change: 1 addition & 0 deletions waspc/data/Cli/templates/basic/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "__waspAppName__",
"type": "module",
"dependencies": {
"wasp": "file:.wasp/out/sdk/wasp",
"react": "^18.2.0"
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions waspc/packages/wasp-config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
dist/
.env
.vscode/
6 changes: 6 additions & 0 deletions waspc/packages/wasp-config/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
26 changes: 26 additions & 0 deletions waspc/packages/wasp-config/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";

export default [
pluginJs.configs.recommended,
...tseslint.configs.strict,
// Todo: explore typed-linting: https://typescript-eslint.io/getting-started/typed-linting
{
languageOptions: {
globals: globals.node,
},
},
// global ignore
{
ignores: ["node_modules/", "dist/"],
},
{
rules: {
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-empty-function": "warn",
"no-empty": "warn",
"no-constant-condition": "warn",
},
},
];
6 changes: 6 additions & 0 deletions waspc/packages/wasp-config/nodemon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"watch": [
"./src/**/*.ts"
],
"exec": "tsc || exit 1"
}
Loading

0 comments on commit e92cb25

Please sign in to comment.