Skip to content

Commit 312ca6d

Browse files
Fix: Vue3 XState cleanup issues (#1276)
* fix: change cursor for buttons; create debug script; fix spelling issue * fix: add engine to package json and enforce with npmrc * fix: simplify readme file * Update starters/vue3-xstate-css/README.md Co-authored-by: Jessica Wilkins <[email protected]> * fix: regenerated starter kit json file --------- Co-authored-by: Jessica Wilkins <[email protected]>
1 parent 97418ec commit 312ca6d

File tree

6 files changed

+18
-88
lines changed

6 files changed

+18
-88
lines changed

starter-kits.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@
1717
"solidstart-tanstackquery-tailwind-modules": "Solid Start, TanStack Query and Tailwind CSS with CSS Modules",
1818
"svelte-kit-scss": "SvelteKit and SCSS",
1919
"vue3-apollo-quasar": "Vue3, Apollo, and Quasar",
20-
"vue3-xstate-css": "Vue 3, XState, and CSS"
20+
"vue3-xstate-css": "Vue3, XState, and CSS"
2121
}

starters/vue3-xstate-css/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
engine-strict=true

starters/vue3-xstate-css/README.md

Lines changed: 4 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ For more setup options, check out our [setup instructions in the wiki](https://g
1818
- [XState](https://xstate.js.org/)
1919
- CSS
2020

21-
This kit is also set up to show the XState visualizer when run locally, to help you see what your state machines look like and how they work.
22-
2321
### Included Tooling
2422

2523
- [Vite](https://vitejs.dev/) - build / bundle tool
@@ -50,6 +48,7 @@ Once you've generated your new starter kit following the instructions above:
5048
## Available commands
5149

5250
- `npm run dev` starts the local development server
51+
- `npm run dev:debug` starts the local dev server and launches the XState visualizer
5352

5453
- `npm run build-only` handles compiling and minifying your files
5554
- `npm run type-check` type checks your files
@@ -83,18 +82,10 @@ The main folder you'll interact with is the `src` folder. This is split into a f
8382

8483
### Using XState
8584

86-
#### The visualizer
87-
88-
To get the visualizer working locally, we're using the `@xstate/inspect` package and importing it within the `main.ts` file. Then within our components, when we want to be able to visualize our state machine we pass the `devtools: true` option when we call `useMachine`. The visualizer allows us to see what a particular state machine looks like by letting us manually trigger different states and actions. You can even directly change the machine within the visualizer to test out changes you might want to make. Just make sure that if you want to keep those changes you copy it back into your machine file!
89-
9085
#### State vs Context
9186

9287
You'll notice that within both of our example machines, we're using a `context` object. You can read more specifics about how this works [in the XState documentation on context](https://xstate.js.org/docs/guides/context.html#initial-context), but in general the context stores data that might be quantitative in nature (like numbers, strings, or objects).
9388

94-
In [the introduction to state machines documentation](https://xstate.js.org/docs/guides/introduction-to-state-machines-and-statecharts/#states), they give the example of a dog's "state" as being asleep or awake. A dog can't be both asleep and awake at the same time - it has to be one or the other. The same is true of our states. You'll see this best in the `greetMachine.ts` file. We're either loading our data, we received our complete data, or we received our error data. The machine can only be in one of these three states.
95-
96-
We use the context to store information that might change as we go through different states. In our greetMachine, we use the context to store the query we're sending, the message we get back, and any potential error text we get back. Since the items here are arbitrary and can change as our machine moves through it's states, we store these in the context object.
97-
9889
#### TS Support in Machines
9990

10091
XState offers us a `schema` option in our machines to allow us to type our state charts. We can use this to help strongly type our context and events. This will give us better tips when using our machine and help ensure we know what types of values we're expecting when we use them.
@@ -103,92 +94,22 @@ XState offers us a `schema` option in our machines to allow us to type our state
10394

10495
The `createMachine` call that we use to build machines accepts two objects.
10596

106-
The first object is always present, and specifies the name of our machine, it's initial state, any local context it needs, and the states our machine can be in.
107-
108-
```js
109-
import { createMachine } from 'xstate';
110-
111-
const lightMachine = createMachine({
112-
// Machine identifier
113-
id: 'light',
114-
115-
// Initial state
116-
initial: 'green',
117-
118-
// Local context for entire machine
119-
context: {
120-
elapsed: 0,
121-
direction: 'east',
122-
},
123-
124-
// State definitions
125-
states: {
126-
green: {
127-
/* ... */
128-
},
129-
yellow: {
130-
/* ... */
131-
},
132-
red: {
133-
/* ... */
134-
},
135-
},
136-
});
137-
```
138-
139-
Eventually our states will need to define actions, services, or guards. These can be written directly within the state itself, or they can be passed to the optional second object in the `createMachine` function, and then referenced in the state by their name.
140-
141-
```js
142-
const lightMachine = createMachine(
143-
{
144-
id: 'light',
145-
initial: 'green',
146-
states: {
147-
green: {
148-
// action referenced via string
149-
entry: 'alertGreen',
150-
},
151-
},
152-
},
153-
{
154-
actions: {
155-
// action implementation
156-
alertGreen: (context, event) => {
157-
alert('Green!');
158-
},
159-
},
160-
guards: {
161-
/* ... */
162-
},
163-
services: {
164-
/* ... */
165-
},
166-
}
167-
);
168-
```
97+
The first object is always present, and specifies the name of our machine, it's initial state, any local context it needs, and the states our machine can be in. Eventually our states will need to define actions, services, or guards. These can be written directly within the state itself, or they can be passed to the optional second object in the `createMachine` function, and then referenced in the state by their name.
16998

17099
You'll see both options in this kit - the `counterMachine` has it's actions defined separately, and the `greetMachine` has the actions inline in the state but the service defined separately. Either option is valid. You might start with your actions inlined to ensure they work, and then separate them out to make them easier to read and debug.
171100

172-
#### Predictable Action Arguments Flag
173-
174-
You'll see the option `predictableActionArguments: true` within our machines. This is recommended per the docs, and will be a default option in the next version. This flag means that XState will always call an action with the direct event that triggered it.
175-
176101
### Vue 3 Benefits
177102

178-
Since we're using Vue 3, we're able to make use of the composition API. This means we can use the `setup` option in our component's script tags, which lets us define our variables and functions in a style that looks a bit more like standard JS. With this method, we don't have to have an object that defines all of the values our component can use - it allows us to use standard variables and functions which can be used directly in our templates.
179-
180-
Another benefit of using Vue 3 is getting to work with the new provide and inject functions. These allow us to set up our own dependency system, so instead of having to deal with prop drilling and passing values along components that don't need them, we can provide that value in a parent component and then inject it into the component that needs it, bypassing all the others.
103+
A key benefit of using Vue 3 is getting to work with the new `provide` and `inject` functions. These allow us to set up our own dependency system, so instead of having to deal with prop drilling and passing values along components that don't need them, we can provide that value in a parent component and then inject it into the component that needs it, bypassing all the others.
181104

182105
You can see an example of this with the `GreetView` component. We needed a way to provide an initial query value, but didn't want to have to set up a prop within the router or drill it down through the home component. So we set up the `provide` function in the `main.ts` file, which makes it globally available in our app to any component that needs it. The `provide` function takes two arguments, a key and a value. Then, our `GreetView` component can inject that value and make use of it. We're also able to set a default value in case the provided key doesn't have a value.
183106

184107
### Cypress Testing
185108

186-
The only specific setup thing we needed to do to enable component testing was to add the `mount` command to Cypress. They have packages available for multiple common frameworks which will provide the functionality for you - all we have to do is go into our `cypress/support/component.ts` file, import the `mount` function, and then tell Cypress to add that command. This lets us mount our individual components so we can then run our Cypress tests directly on that component.
109+
The only specific setup thing we needed to do to enable component testing was to add the `mount` command to Cypress. They have packages available for multiple common frameworks which will provide the functionality for you - all we have to do is go into our `cypress/support/component.ts` file, import the `mount` function, and then tell Cypress to add that command.
187110

188111
To enable our tests to also be able to access our provided value in the `GreetView` component, we've customized the provided `mount` function so that we provide an initial value. Then, for each test that needs to mount the component, we can either provide it with nothing (thus allowing our default value to be tested) or give it a custom message just for our tests to ensure everything works as expected.
189112

190-
That `cypress/support/component.ts` file is also where you'll import any global styles your components might need.
191-
192113
## Deployment
193114

194115
Deploying to a hosting service like [Netlify](https://www.netlify.com) or [Vercel](https://vercel.com) is as straight forward as hooking up your repository to the service and letting the service auto detect the configuration for you.

starters/vue3-xstate-css/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
{
22
"name": "vue3-xstate-css",
33
"version": "0.0.0",
4-
"description": "Vue 3, XState, and CSS",
4+
"description": "Vue3, XState, and CSS",
55
"keywords": [
66
"vue",
77
"xstate",
88
"css"
99
],
1010
"hasShowcase": false,
11+
"engines": {
12+
"node": "16.18"
13+
},
1114
"scripts": {
1215
"dev": "vite",
16+
"dev:debug": "VITE_DEV_MODE='debug' vite",
1317
"build": "run-p type-check build-only",
1418
"preview": "vite preview",
1519
"test:unit": "cypress run --component",

starters/vue3-xstate-css/src/components/ButtonComponent.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ button {
1616
padding: 0.5em 0.25em;
1717
border-radius: 4px;
1818
border-color: var(--lightBlue);
19+
cursor: pointer;
1920
}
2021
2122
@media screen and (max-width: 768px) {

starters/vue3-xstate-css/src/main.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import { inspect } from '@xstate/inspect';
55

66
import './assets/main.css';
77

8-
inspect({
9-
iframe: false,
10-
});
8+
const devMode = import.meta.env.VITE_DEV_MODE;
9+
if (devMode === 'debug') {
10+
inspect({
11+
iframe: false,
12+
});
13+
}
1114

1215
const app = createApp(App);
1316

0 commit comments

Comments
 (0)