Skip to content
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
af0573b
Tutorial app from Markdown WIP
infomiho May 9, 2025
f30e545
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho May 16, 2025
f25bca5
Cleanup
infomiho May 16, 2025
a7d35a6
Parse diffs
infomiho May 16, 2025
04287c7
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho May 19, 2025
c29048e
Edit diff DX
infomiho May 19, 2025
373e563
Move patches outside of Markdown. Implement fixing broken diffs
infomiho May 19, 2025
8cf25a8
Cleanup
infomiho May 19, 2025
778602d
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Jul 16, 2025
72c0964
Cleanup
infomiho Jul 16, 2025
2a41ada
Named patches WIP
infomiho Jul 16, 2025
e7546b5
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Jul 17, 2025
10c1f1c
Update TutorialAction component
infomiho Jul 17, 2025
d00d7db
Update TutorialAction design
infomiho Jul 17, 2025
6a4a290
Stop using write action
infomiho Jul 17, 2025
0a2f90f
Cleanup
infomiho Jul 17, 2025
3ce2ca3
Cleanup
infomiho Jul 17, 2025
de1ad8a
Cleanup
infomiho Jul 17, 2025
1110026
Restructure
infomiho Jul 17, 2025
eee3f77
Refactor. Add edit step command.
infomiho Jul 17, 2025
3ea8530
Branded types, cleanup
infomiho Jul 17, 2025
c20ea08
Revert change to search-and-replace.ts
infomiho Jul 18, 2025
1348c89
Cleanup TutorialAction
infomiho Jul 18, 2025
69149ae
Cleanup
infomiho Jul 18, 2025
7ba6f4a
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Jul 18, 2025
d981153
Update styles
infomiho Jul 18, 2025
66b0fa8
Fixes patch fixing bug. Update patches.
infomiho Jul 31, 2025
8b3fe23
PR comments
infomiho Aug 4, 2025
5ad4372
Cleanup
infomiho Aug 5, 2025
f0d6ec3
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Aug 6, 2025
6522952
Formatting
infomiho Aug 6, 2025
80095ad
PR comments
infomiho Aug 6, 2025
f81a05d
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Aug 8, 2025
4e964f3
Refactor code
infomiho Aug 8, 2025
dc7fd21
Rename folder and update README
infomiho Aug 8, 2025
845e146
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Sep 12, 2025
4aa1173
PR comments
infomiho Sep 12, 2025
3af974a
Update naming
infomiho Sep 12, 2025
04f9ade
Move app init into a separate action
infomiho Sep 12, 2025
b3f9aae
PR comments
infomiho Sep 12, 2025
551679d
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Sep 15, 2025
1814a72
Update README
infomiho Sep 15, 2025
a2d043f
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Sep 29, 2025
ec4ec93
PR comments
infomiho Sep 29, 2025
fe58646
PR comments
infomiho Sep 29, 2025
6390e92
PR comments
infomiho Sep 29, 2025
939c066
Add unit tests
infomiho Sep 29, 2025
db7d68c
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Oct 6, 2025
aea3c6d
Update code block language
infomiho Oct 6, 2025
7c03e0c
Cleanup README
infomiho Oct 6, 2025
9ecdbd6
Wrap all steps with <TutorialAction> component
infomiho Oct 6, 2025
a28fa0c
Merge branch 'main' into miho-tutorial-app-from-docs
infomiho Oct 10, 2025
f78f56a
PR comments
infomiho Oct 10, 2025
19aec40
Update sort and filter fn names
infomiho Oct 10, 2025
85ff579
Extract example MDX files
infomiho Oct 10, 2025
f65fb22
Remove Git explanantion and update action name
infomiho Oct 10, 2025
7a1a3da
Update actions to action types
infomiho Oct 10, 2025
9dff3f1
Handle both md and mdx extensions
infomiho Oct 10, 2025
0ef5164
Update naming
infomiho Oct 10, 2025
6c3935d
Cleanup JSDoc
infomiho Oct 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions web/docs/tutorial/03-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
import { ShowForTs } from '@site/src/components/TsJsHelpers';
import WaspStartNote from '../\_WaspStartNote.md'
import TypescriptServerNote from '../\_TypescriptServerNote.md'
import { TutorialAction } from './TutorialAction';

In the default `main.wasp` file created by `wasp new`, there is a **page** and a **route** declaration:

Expand Down Expand Up @@ -47,7 +48,7 @@ import './Main.css';

export function MainPage() {
// ...
}
};
```

This is a regular functional React component. It also imports some CSS and a logo from the `assets` folder.
Expand All @@ -74,12 +75,12 @@ page HelloPage {
When a user visits `/hello/their-name`, Wasp renders the component exported from `src/HelloPage.{jsx,tsx}` and you can use the `useParams` hook from `react-router-dom` to access the `name` parameter:

```tsx title="src/HelloPage.tsx" auto-js
import { useParams } from 'react-router-dom'
import { useParams } from "react-router-dom";

export const HelloPage = () => {
const { name } = useParams<'name'>()
return <div>Here's {name}!</div>
}
const { name } = useParams<"name">();
return <div>Here's {name}!</div>;
};
```

Now you can visit `/hello/johnny` and see "Here's johnny!"
Expand All @@ -96,12 +97,14 @@ Now that you've seen how Wasp deals with Routes and Pages, it's finally time to

Start by cleaning up the starter project and removing unnecessary code and files.

<TutorialAction id="prepare-project" action="apply-patch" />

First, remove most of the code from the `MainPage` component:

```tsx title="src/MainPage.tsx" auto-js
export const MainPage = () => {
return <div>Hello world!</div>
}
return <div>Hello world!</div>;
};
```

At this point, the main page should look like this:
Expand Down
4 changes: 4 additions & 0 deletions web/docs/tutorial/04-entities.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ title: 4. Database Entities
---

import useBaseUrl from '@docusaurus/useBaseUrl';
import { TutorialAction } from './TutorialAction';

Entities are one of the most important concepts in Wasp and are how you define what gets stored in the database.

Wasp uses Prisma to talk to the database, and you define Entities by defining Prisma models in the `schema.prisma` file.

Since our Todo app is all about tasks, we'll define a Task entity by adding a Task model in the `schema.prisma` file:

<TutorialAction id="prisma-task" action="apply-patch" />
Copy link
Member

Choose a reason for hiding this comment

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

Aha, so TutorialAction has no content/children. I don't know why I thought that the content below (the code block) would go into the component itself, but that wouldn't make much sense, would it? Maybe semantically it would, but it would make problems for rendering here or something?

Copy link
Contributor

Choose a reason for hiding this comment

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

Well one thing is that these files are really .mdx not .md.
It's basically markdown and JSX in javascript.
In the end the whole this file gets converted to pure javascript, same as .jsx/.tsx files.

So it should be possible to insert all of the content related to <TutorialAction/> as its children.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, at first I put the content inside - but it proved problematic for other plugins (auto-js) dealing with the Markdown AST. I opted for the simplest solution of not wrapping it, even thought... it would be pretty sweet to see the action text wrapped with a red border. Maybe in some next version of this system...

Copy link
Member

Choose a reason for hiding this comment

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

Ha ok! I wonder if we could document this somewhere for the person looking at it int he future, maybe attempting to do this improvement?

Btw what was the issue with auto-js for example?

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, now that I tested it again I remembered what was wrong. I was trying to parse the children of <TutorialAction> way back when I had different actions for creating file and applying patches.

<TutorialAction action="create-file">
```tsx auto-js
const some = "code";
```
</TutorialAction>

This would try to parse the code block but sometimes it would fail (I forget the exact error) and I found it working with blocks without auto-js transformation.

Now that we only use patches, we are no longer parsing the children - we can actually wrap each code block with <TutorialAction> now 😄

Copy link
Contributor Author

@infomiho infomiho Oct 6, 2025

Choose a reason for hiding this comment

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

Wrapped all steps now properly, it renders like this now and it works :)

SCR-20251006-neam


```prisma title="schema.prisma"
// ...

Expand All @@ -26,6 +29,7 @@ Read more about how Wasp Entities work in the [Entities](../data-model/entities.

To update the database schema to include this entity, stop the `wasp start` process, if it's running, and run:

<TutorialAction id="migration-add-task" action="migrate-db" />
```sh
wasp db migrate-dev
```
Expand Down
44 changes: 26 additions & 18 deletions web/docs/tutorial/05-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ title: 5. Querying the Database

import useBaseUrl from '@docusaurus/useBaseUrl';
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers';
import { TutorialAction } from './TutorialAction';

We want to know which tasks we need to do, so let's list them!

Expand Down Expand Up @@ -39,9 +40,11 @@ We need to add a **query** declaration to `main.wasp` so that Wasp knows it exis
entities: [Task]
}
```

</TabItem>

<TabItem value="ts" label="TypeScript">
<TutorialAction id="query-get-tasks" action="apply-patch" />
```wasp title="main.wasp"
// ...

Expand All @@ -59,6 +62,7 @@ We need to add a **query** declaration to `main.wasp` so that Wasp knows it exis
:::note
To generate the types used in the next section, make sure that `wasp start` is still running.
:::

</TabItem>
</Tabs>

Expand All @@ -72,15 +76,17 @@ We need to add a **query** declaration to `main.wasp` so that Wasp knows it exis
Next, create a new file called `src/queries.ts` and define the TypeScript function we've just imported in our `query` declaration:
</ShowForTs>

<TutorialAction id="query-get-tasks-impl" action="apply-patch" />

```ts title="src/queries.ts" auto-js
import type { Task } from 'wasp/entities'
import type { GetTasks } from 'wasp/server/operations'
import type { Task } from "wasp/entities";
import type { GetTasks } from "wasp/server/operations";

export const getTasks: GetTasks<void, Task[]> = async (args, context) => {
return context.entities.Task.findMany({
orderBy: { id: 'asc' },
})
}
orderBy: { id: "asc" },
});
};
```

<ShowForTs>
Expand Down Expand Up @@ -116,25 +122,27 @@ While we implement Queries on the server, Wasp generates client-side functions t

This makes it easy for us to use the `getTasks` Query we just created in our React component:

<TutorialAction id="main-page-tasks" action="apply-patch" />

```tsx title="src/MainPage.tsx" auto-js
import type { Task } from 'wasp/entities'
import type { Task } from "wasp/entities";
// highlight-next-line
import { getTasks, useQuery } from 'wasp/client/operations'
import { getTasks, useQuery } from "wasp/client/operations";

export const MainPage = () => {
// highlight-start
const { data: tasks, isLoading, error } = useQuery(getTasks)
const { data: tasks, isLoading, error } = useQuery(getTasks);

return (
<div>
{tasks && <TasksList tasks={tasks} />}

{isLoading && 'Loading...'}
{error && 'Error: ' + error}
{isLoading && "Loading..."}
{error && "Error: " + error}
</div>
)
);
// highlight-end
}
};

// highlight-start
const TaskView = ({ task }: { task: Task }) => {
Expand All @@ -143,20 +151,20 @@ const TaskView = ({ task }: { task: Task }) => {
<input type="checkbox" id={String(task.id)} checked={task.isDone} />
{task.description}
</div>
)
}
);
};

const TasksList = ({ tasks }: { tasks: Task[] }) => {
if (!tasks?.length) return <div>No tasks</div>
if (!tasks?.length) return <div>No tasks</div>;

return (
<div>
{tasks.map((task, idx) => (
<TaskView task={task} key={idx} />
))}
</div>
)
}
);
};
// highlight-end
```

Expand All @@ -172,7 +180,7 @@ Most of this code is regular React, the only exception being the <ShowForJs>two<
- `useQuery` - Wasp's [useQuery](../data-model/operations/queries#the-usequery-hook-1) React hook, which is based on [react-query](https://github.com/tannerlinsley/react-query)'s hook with the same name.
- `Task` - The type for the Task entity defined in `schema.prisma`.

Notice how you don't need to annotate the type of the Query's return value: Wasp uses the types you defined while implementing the Query for the generated client-side function. This is **full-stack type safety**: the types on the client always match the types on the server.
Notice how you don't need to annotate the type of the Query's return value: Wasp uses the types you defined while implementing the Query for the generated client-side function. This is **full-stack type safety**: the types on the client always match the types on the server.
</ShowForTs>

We could have called the Query directly using `getTasks()`, but the `useQuery` hook makes it reactive: React will re-render the component every time the Query changes. Remember that Wasp automatically refreshes Queries whenever the data is modified.
Expand Down
Loading