From 7743e075108bd3b56044de4bbfc5717fbd1b62cc Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 18:57:09 +0100 Subject: [PATCH 1/9] reactivity recipe --- README.md | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/README.md b/README.md index 7267b3a..791cf7c 100644 --- a/README.md +++ b/README.md @@ -264,3 +264,223 @@ You now have all you need to work with Data APIs in Svelte. ## How to make a pre-processor that makes it possible to use PUG/Jade *to be written* + +## Reactivity + +### Reactive assignments + +The reactivity system introduced in Svelte 3 has made it easier than ever to trigger updates to the DOM. Despite this, there are a few simple rules that you must always follow. This guide explains how Svelte's reactivity system works, what you can and can't do, as well a few pitfalls to avoid. + +#### Top-level variables + +The simplest way to make your Svelte components reactive is by using an assignment operator. Any time Svelte sees an assignment to a *top-level variable* an update is scheduled. A 'top-level variable' is any variable that is defined inside the script element but is not a child of *anything*, meaning, it is not inside a function or a block. Incidentally, these are also the only variables that you can reference in the DOM. Let's look at some examples. + +The following works as expected and update the dom: + +```sv + + + +

{num}

+``` + +Svelte can see that there is an assignment to a top-level variable and knows to rerender after the `num` variable is modified. + +#### `each` blocks + +The only exception to the top-level variable rule is when you are inside an `each` block. Any assignments to variables inside an `each` block trigger an update. Only assignments to array items that are objects or arrays result in the array itself updating. If the array items are primitives, the change is not traced back to the original array. This is because Svelte only reassigns the actual array items and primitives are passed by value in javascript, not by reference. + +The following example causes the array and, subsequently, the DOM to be updated: + +```sv + + +{#each list as item} + +{/each} +``` + +This, however, will not: + +```sv + + +{#each list as item} + +{/each} +``` + +#### Variables not values + +Svelte only cares about which *variables* are being reassigned, not the values to which those variables refer. If the variable you reassign is not defined at the top level, Svelte does not trigger an update, even if the value you *are* updating updates the original variable's value as well. + +This is the sort of problem you may run into when dealing with objects. Since objects are passed by reference and not value, you can refer to the same value in many different variables. Let's look at an example: + +```sv + + + +

{obj.num}

+``` + +In this example, when we reassign `o.num` we are updating the value assigned to `obj` but since we are not updating the actual `obj` variable SVelte does not trigger an update. Svelte does not trace these kinds of values back to a variable defined at the top level and has no way of knowing if it has updated or not. Whenever you want to update the local component state, any reassignments must be performed on the *actual* variable, not just the value itself. + +#### Shadowed variables + +Another situation that can sometimes cause unexpected results is when you reassign a function's parameter (as above), and that parameter has the same *name* as a top-level variable. + +```sv + + + +

{num}

+``` + +This example behaves the same as the previous example, except it is perhaps even more confusing. In this case, the `obj` variable is being *shadowed* while inside the function, so any assignments to `obj` inside this function are assignments to the function parameter rather than the top-level `obj` variable. It refers to the same value, and it has the same name, but it is a *different* variable inside the function scope. + +Reassigning function parameters in this way is the same as reassigning a variable that points back to the top-level variable's value and does not cause an update. To avoid these problems, and potential confusion, it is a good idea not to reuse variable names in different scopes (such as inside functions), and always make sure that you are reassigning a top-level variable. + + +### Reactive Declarations + +In addition to the assignment-based reactivity system, Svelte also has special syntax to define code that should rerun when its dependencies change using labeled statements - `$: `. + +```sv + + + +``` + +Whenever Svelte sees a reactive declaration, it makes sure to execute any reactive statements that depend on one another in the correct order and only when their direct dependencies have changed. A 'direct dependency' is a variable that is referenced inside the reactive declaration itself. References to variables inside functions that a reactive declaration *calls* are not considered dependencies. + +```sv + + + +``` + +In the above example, `n_squared` will *not* be recalculated when `n` changes because Svelte is not looking inside the `squareIt` function to define the reactive declaration's dependencies. + +#### Defining dependencies + +Sometimes you want to rerun a reactive declaration when a value changes but the variable itself is not required (in the case of some side-effects). The solution to this involves listing the dependency inside the declaration in some way. + +The simplest solution is to pass the variable as an argument to a function, even if that variable is not required. + +```js +let my_value = 0; + +function someFunc() { + console.log(my_value); +} + +$: someFunc(my_value); +``` + +In this example, `someFunc` doesn't require the `my_value` argument, but this lets Svelte know that `my_value` is a dependency of this reactive declaration and should rerun whenever it changes. In general, it makes sense to use any parameters that are passed in, even though all of these variables are in scope, it can make the code easier to follow. + +```js +let my_value = 0; + +function someFunc(value) { + console.log(value); +} + +$: someFunc(my_value); +``` + +Here we have refactored `someFunc` to take an argument, making the code easier to follow. + +If you need to list multiple dependencies and passing them as arguments is not an option, then the following pattern can be used: + +```js +let one; +let two; +let three; + +const someFunc = () => sideEffect(); + +$: one, two, three, someFunc(); +``` + +This simple expression informs Svelte that it should rerun whenever `one`, `two`, or `three` changes. This expression runs the line of code whenever these dependencies change. + +Similarly, if you only want to rerun a function when a variable changes *and* is truthy then you can use the following pattern: + +```js +let one; + +const someFunc = () => sideEffect(); + +$: one && someFunc(); +``` + +If the value of `one` is not truthy, then this short circuit expression stops at `one` and `someFunc` is not executed. + +#### Variable deconstruction + +Assigning a new value in a reactive declaration essentially turns these declarations into computed variables. However, deconstructing an object or array inside a reactive declaration may seem verbose or even impossible at first glance. + +since `$: const { value } = object` is not valid javascript, we need to take a different approach. You can deconstruct values using reactive declarations by forcing javascript to interpret the statement as an expression. + +To achieve this, all we need to do is wrap the declaration with parentheses: + +```js +let some_obj = { one: 1, two: 2, three: 3 } + +$: ({ one, two, three } = some_obj); +``` + +Javascript interprets this as an expression, deconstructing the value as expected with no unnecessary code required. + +#### Hiding values from reactive declarations + +On ocassion, you may wish to run a reactive declaration when only *some* of its dependencies change, in essence, you need to *hide* specific dependencies from Svelte. This is the opposite case of declaring additional dependencies and can be achieved by not referencing the dependencies in the reactive declaration but *hiding* those references in a function. + +```js +let one; +let two; + +const some_func = n => console.log(n * two); + +$: some_func(one); +``` + +The reactive declaration in this example reruns *only* when `one` changes, we have hidden the reference to `two` inside a function because Svelte does not look inside of referenced functions to track dependencies. From 564d5b5269e9b7d89c5c65ef13c2e94a939c1f6b Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:00:37 +0100 Subject: [PATCH 2/9] stores recipe --- README.md | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) diff --git a/README.md b/README.md index 791cf7c..85dfb19 100644 --- a/README.md +++ b/README.md @@ -484,3 +484,197 @@ $: some_func(one); ``` The reactive declaration in this example reruns *only* when `one` changes, we have hidden the reference to `two` inside a function because Svelte does not look inside of referenced functions to track dependencies. + + +## Stores + +> _This guide assumes you understand the basics of Svelte Stores. If you aren't familiar with them then working through the [relevant tutorial](tutorial/writable-stores) and reading the [store documentation](docs#svelte_store) are highly recommended._ + +Svelte stores offer a simple mechanism to handle shared state in your Svelte application but looking beyond the built-in store implementations will unlock a whole world of power that you could never have dreamed of. In this episode of _The Tinest Kitchen_ we'll take a close look at [The Store Contract](#The_Store_Contract), learn how to implement [Custom Stores](#Custom_Stores), by making use of the built-in store API, and explore how we can implement [a completely custom store]() without using the built-in stores at all. + +### The store contract + +The built-in Svelte stores (`readable`, `writable`, and `derived`) are just store _implementations_ and while they are perfectly capable of handling many tasks, sometimes you need something more specific. Although often overlooked, the store _contract_ is what gives these stores their power and flexibility. Without this contract, svelte stores would be awkward to use and require significant amounts of boilerplate. + +Svelte does not compile your javascript files and, as such, only observes the store contract inside Svelte components. + +#### `store.subscribe` + +At its simplest, the store contract is this: any time Svelte sees a variable prepended with `$` in a Svelte component (such as `$store`) it calls the `subscribe` method of that variable. The `subscribe` method must take a single argument, which is a function, and it must _return_ a function that allows any subscribers to unsubscribe when necessary. Whenever the callback function is called, it must be passed the current store value as an argument. The callback passed to subscribe should be called when subscribing and anytime the store value changes. + +The following examples aren't the _exact_ code that Svelte produces, rather, simplified examples to illustrate the behaviour. + +This: + +```js +import { my_store } from './store.js'; + +console.log($my_store); +``` + +Becomes something like this: + +```js +import { my_store } from './store.js'; + +let $my_store; +const unsubscribe = my_store.subscribe(value => ($my_store = value)); +onDestroy(unsubscribe); + +console.log($my_store); +``` + +The callback function passed to `my_store.subscribe` is called immediately and whenever the store value changes. Here, Svelte has automatically produced some code to assign the `my_store` value to `$my_store` whenever it is called. If `$my_store` is referenced in the component, it also causes those parts of the component to update when the store value changes. When the component is destroyed, Svelte calls the unsubscribe function returned from `my_store.subscribe`. + +#### `store.set` + +Optionally, a store can have a `set` method. Whenever there is an assignment to a variable prepended with `$` in a Svelte component it calls the `set` method of that variable with newly mutated or reassigned `$variable` as an argument. Typically, this `set` argument should update the store value and call all subscribers, but this is not required. For example, Svelte's `tweened` and `spring` stores do not immediately update their values but rather schedule updates on every frame for as long as the animation lasts. If you decide to take this approach with `set`, we advise not [binding](tutorial/store-bindings) to these stores as the behaviour could be unpredictable. + +This: + +```js +$my_store = 'Hello'; +``` + +Will become something like: + +```js +$my_store = 'Hello'; +my_store.set($my_store); +``` + +The same is true when assigning to a nested property of a store. + +This: + +```js +$my_store.greeting = 'Hello'; +``` + +Becomes: + +```js +$my_store.greeting = 'Hello'; +my_store.set($my_store); +``` + +Although Svelte's built-in stores also have an `update` method, this is not part of the contract and is not required to benefit from the automatic subscriptions, unsubscriptions, and updates that the store contract provides. Stores can have as many additional methods as you like, allowing you to build powerful abstractions that take advantage of the automatic reactivity and cleanup that the store contract provides. + +To summarise, the store contract states that svelte stores must be an object containing the following methods: + +- `subscribe` - Automatically called whenever svelte sees a `$` prepended variable (like `$store`) ensuring that the `$` prepended value always has the current store value. Subscribe must accept a function which is called both immediately, and whenever the store value changes, it must return an unsubscribe function. The callback function must be passed the current store value as an argument whenever it is called. +- `set` - Automatically called whenever Svelte sees an assignment to a `$` prepended variable (like `$store = 'value'`). This should generally update the store value and call all subscribers. + +### Custom stores + +Now we know what Svelte needs to make use of the shorthand store syntax, we can get to work implementing a custom store by augmenting a svelte store and re-exporting it. Since Svelte doesn't care about additional methods being present on store objects, we are free to add whatever we like as long as `subscribe`, and optionally `set`, are present. + +#### Linked stores + +In this first example, we are creating a function that returns two linked stores that update when their partner changes, this example uses this linked store to convert temperatures from Celsius to Fahrenheit and vice-versa. The interface looks like this: + +```js +store : { subscribe, set } +function(a_to_b_function, b_to_a_function): [store, store] +``` + +To implement this store, we need to create two writable stores, write custom `set` methods for each, and return an array of store objects containing this `set` method. + +We define a function first as this implementation is a store _creator_ allowing us plenty of flexibility. The function needs to take two parameters, each being a callback function which is called when the stores are updated. The first function takes the first store value and returns a value that sets the value of the second store. The second argument does the opposite. One of these functions is called when the relevant `set` method is called. + +```js +import { writable } from 'svelte/store'; + +function synced(a_to_b, b_to_a) { + const a = writable(); + const b = writable(); +} +``` + +The `set` methods call their own `set` with the provided value and call the partner store's `set` when the provided value is passed through the callback function. + +```js +// called when store_a.set is called or its binding reruns +function a_set($a) { + a.set($a); + b.set(a_to_b($a)); +} + +// called when store_b.set is called or its binding reruns +function b_set($b) { + b.set(b_to_a($b)); + a.set($b); +} +``` + +All we need to do now is return an array of objects each containing the correct `subscribe` and `set` method: + +```js +return [ + { subscribe: a.subscribe, set: a_set }, + { subscribe: b.subscribe, set: b_set }, +]; +``` + +Inside a component, we can use this synced store creator by deconstructing the returned array. This ensures Svelte can subscribe to each store individually, as stores definitions need to be at the top level for this to happen. This store can be imported and reused in any component. + +```js +import { synced } from './synced.js'; + +const [a, a_plus_five] = synced( + a => a + 5, + b => a - 5 +); + +$c = 0; // set an initial value +``` + +Since we have written custom `set` methods, we are also free to bind to each individual store. When one store updates, the other also updates after the provided function is applied to the value. + +See it in action below. The following example uses the `synced` store to convert between Celsius and Fahrenheit in both directions. + +
+ +
+ +*the stuff i actually wrote ends here, this is a fun example that could be included though* + +### a custom implementation of the builtin store + +A simple store is about 20 lines of code, in many cases the built-in stores provide good primitives you can build on but sometimes it makes sense to write your own. + +The most basic implementation would look something like this ([REPL](https://svelte.dev/repl/1c055b975b6d42f5b8623bad5d92e8fc?version=3.14.0)) (this is simpler than the built-in stores): + +```js +function writable(init) { + let _val = init; + const subs = []; + + const subscribe = cb => { + subs.push(cb); + cb(_val); + + return () => { + const index = subs.findIndex(fn => fn === cb); + subs.splice(index, 1); + }; + }; + + const set = v => { + _val = v; + subs.forEach(fn => fn(_val)); + }; + + const update = fn => set(fn(_val)); + + return { subscribe, set, update }; +} +``` + +From this point you could add whatever functionality you wanted. + +Edit: Probably worth mentioning that this is a full writable implementation, only the subscribe method and its return value (an unsubscribe function) are required to be a valid store. From ffd57fa808f7e7b2ba388255d4b318b4be59958f Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:03:39 +0100 Subject: [PATCH 3/9] routing placeholder --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 85dfb19..496a1c6 100644 --- a/README.md +++ b/README.md @@ -678,3 +678,11 @@ function writable(init) { From this point you could add whatever functionality you wanted. Edit: Probably worth mentioning that this is a full writable implementation, only the subscribe method and its return value (an unsubscribe function) are required to be a valid store. + +## Routing + +- A map for an app: what is routing +- Different approaches + - XML-stylee: [svelte-routing](https://github.com/EmilTholin/svelte-routing) + - Express-stylee: [navaid](https://github.com/lukeed/navaid) + - FS based routing: [routify](https://routify.dev/) From 06beca46f49b794c94fc3405cc18fcfddf44c75d Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:04:54 +0100 Subject: [PATCH 4/9] ssr placeholder --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 496a1c6..5704259 100644 --- a/README.md +++ b/README.md @@ -686,3 +686,12 @@ Edit: Probably worth mentioning that this is a full writable implementation, onl - XML-stylee: [svelte-routing](https://github.com/EmilTholin/svelte-routing) - Express-stylee: [navaid](https://github.com/lukeed/navaid) - FS based routing: [routify](https://routify.dev/) + +## Server Side Rendering + +- What is it +- What does the API look like +- building an SSR component +- hydrating an SSR cmponent with a client build +- building a simple express-based SSR server thing +- putting it all together From 7017dedcfe52e15765e9ac8c0e9dd7ca399da8f8 Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:05:56 +0100 Subject: [PATCH 5/9] preprocessor placeholder thing --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 5704259..e9717b7 100644 --- a/README.md +++ b/README.md @@ -695,3 +695,32 @@ Edit: Probably worth mentioning that this is a full writable implementation, onl - hydrating an SSR cmponent with a client build - building a simple express-based SSR server thing - putting it all together + + +## Preprocessors + +> This article references `svelte.preprocess` throughout but you may be more familiar with the `preprocess` option of `svelte-loader` or `rollup-plugin-svelte`. This `preprocess` option calls `svelte.preprocess` internally. The bundler plugin gives you easy access to it, so you don't need to transform your components before compilation manually. + +The Svelte compiler expects all components it receives to be valid Svelte syntax. To use compile-to-js or compile-to-css languages, you need to make sure that any non-standard syntax is transformed before Svelte tries to parse it. To enable this Svelte provides a `preprocess` method allowing you to transform different parts of the component before it reaches the compiler. + +With `svelte.preprocess` you have a great deal of flexibility in how you write your components while ensuring that the Svelte compiler receives a plain component. + +### `svelte.preprocess` + +Svelte's `preprocess` method expects an object or an array of objects with one or more of `markup`, `script`, and `style` properties, each being a function receiving the source code as an argument. The preprocessors run in this order. + +```js +const preprocess = { + markup, + script, + style +} +``` + +In general, preprocessors receive the component source code and must return the transformed source code, either as a string or as an object containing a `code` and `map` property. The `code` property must contain the transformed source code, while the `map` property can optionally contain a sourcemap. The sourcemap is currently unused by Svelte. + +### Markup preprocessors + +### Script preprocessors + +### Style preprocessors From 7fdf51feb55a5b337e409482ac6d543f8fab9444 Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:16:06 +0100 Subject: [PATCH 6/9] expand testing section --- README.md | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/README.md b/README.md index e9717b7..7eae851 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,149 @@ You now have all you need to work with Data APIs in Svelte. ## Unit Testing Svelte Components +*Some assumptions here, thos was pulled from something i wrote and the context was different. Edits will be required.* + +When testing svelte components in a node environment and using them outside of a Svelte application, we will be mostly interacting programmatically with Svelte’s client-side API as well as the helpers found in @testing-library/svelte. + +### Creating a component + +Creating a component is as simple as passing the component constructor, and any initial props, to the provided render function. + +```js +import { render } from "@testing-library/svelte"; +import Button from "../src/Button.svelte"; + +test("should render", () => { + const results = render(Button, { props: { label: "a button" } }); + + expect(() => results.getByLabelText("a button")).not.toThrow(); +}) +``` + +`results` is an object containing a series of methods that can be used to query the rendered component in a variety of ways. You can see a list of all query methods in the testing-library documentation [link]. + +### Changing component props + +A components props can be changed or set by calling the .$set method of the component itself. results also has a component key which contains the component instance giving us access to svelte’s full client-side API. + +Svelte schedules all component updates for completion asynchronously in the next microtask. Awaiting the action that triggers that microtask will ensure that the component has been updated before proceeding through the code. This also applies to any Svelte component update, regardless of whether it is programmatically changed (via component.$set) or via a ‘user’ action (such as clicking a button). For this to work we need to make sure that we make the test’s callback function async, so we can use await in the body. + +```js +import { render } from "@testing-library/svelte"; +import Button from "../src/Button.svelte"; + +test("should render", async () => { + const { getByLabelText, component } = render(Button, { props: { label: "a button" } }); + + await component.$set({ label: "another button" }); + expect(() => results.getByLabelText("another button")).not.toThrow(); +}); +``` + +### Testing component events + +Component events have a different API to props and it is important we take the time to test them correctly. We will use a combination of jest mock functions and the svelte event API to make sure our component event is calling the provided handler. We can provide an event handler to a component event via a component's .$on method. The .$on method returns and off method, if we need to remove the listener. + +```js +import { render, fireEvent } from "@testing-library/svelte"; +import Button from "../src/Button.svelte"; + +test("events should work", () => { + const { getByLabelText, component } = render(Button, { props: { label: "a button" } }); + + const mock = Jest.fn(); + const button = getByLabelText("a button"); + + component.$on("submit", mock); + fireEvent.click(button); + + expect(mock).toHaveBeenCalled(); +}); +``` + +### Testing slots + +Slots are more difficult to test as there is no programmatic interface for working with them either inside or outside of a Svelte component. The simplest way is to create a test specific component that utilises a dynamic component to and passes in a default slot to that component which can be asserted against. In this example the component passed as a prop will be used as the containing or parent component of the slotted child content. + +```svelte + + + +

Test Data

+
+``` + +Then the component you wish to test can be passed to the constructor as a prop in order to mount the component correctly: + +```js +import { render } from "@testing-library/svelte"; + +import SlotTest from "./SlotTest.svelte"; +import ComponentToBeTested from "./ComponentToBeTested.svelte"; + +test('it should render slotted content', () => { + const { getByTestId } = render(SlotTest, { props: { Component: ComponentToBeTested } }); + + expect(getByTestId("slot")).not.toThrow(); +}) +``` + +### Testing the context API + +As with slots, there is no programmatic interface for the Context API (setContext, getContext). If you are testing a component, in isolation, that would normally have a parent setting a context to be read by a child, then the simplest solution is to use a test specific parent. This is similar to the approach we used when testing slots. A test component might look something like this. + +```svelte + + + +``` + +The component we wish to test looks something like this: + +```svelte + + + +``` + +We can test this like so: + +```js +import { render } from "@testing-library/svelte"; + +import ContextTest from "./ContextTest.svelte"; +import ComponentToBeTested from "./ComponentToBeTested.svelte"; +// Context is keyed, we need to get the actual key to ensure the correct context is selected by the child. +import { KEY } from "./OriginalParentComponent.svelte"; + +test('it should render slotted content', () => { + const { getByRole } = render(ContextTest, { + props: { + Component: ComponentToBeTested, + context_key: KEY, + context_value: { title: 'Hello' } + } + }); + const button = getByRole('button'); + + expect(button.innerHTML).toBe('Hello') +}) +``` + *to be written* ## Creating Custom Scroll Actions with Svelte From 877f96b041adbb763fbe579abd71391bbf1958e4 Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:17:10 +0100 Subject: [PATCH 7/9] run doctoc --- .github/ISSUE_TEMPLATE/ask-a-question.md | 8 +++++++ .github/ISSUE_TEMPLATE/propose-recipe.md | 8 +++++++ README.md | 27 ++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/ask-a-question.md b/.github/ISSUE_TEMPLATE/ask-a-question.md index 33c1216..674d827 100644 --- a/.github/ISSUE_TEMPLATE/ask-a-question.md +++ b/.github/ISSUE_TEMPLATE/ask-a-question.md @@ -1,3 +1,11 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Ask A Question](#ask-a-question) + + + --- name: Ask a Question about: Ask a question about a Recipe, get answers! We may ask you to contribute a diff --git a/.github/ISSUE_TEMPLATE/propose-recipe.md b/.github/ISSUE_TEMPLATE/propose-recipe.md index 386694b..ba176dd 100644 --- a/.github/ISSUE_TEMPLATE/propose-recipe.md +++ b/.github/ISSUE_TEMPLATE/propose-recipe.md @@ -1,3 +1,11 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Proposed Recipe](#proposed-recipe) + + + --- name: Propose Recipe about: Suggest a Recipe to Add diff --git a/README.md b/README.md index 7eae851..10c86e2 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,11 @@ All examples have some variation "with Svelte" appended to them in an attempt to - [Editable SVG Icon Systems with Svelte](#editable-svg-icon-systems-with-svelte) - [Create a CMS-Powered Blog with Svelte](#create-a-cms-powered-blog-with-svelte) - [Unit Testing Svelte Components](#unit-testing-svelte-components) + - [Creating a component](#creating-a-component) + - [Changing component props](#changing-component-props) + - [Testing component events](#testing-component-events) + - [Testing slots](#testing-slots) + - [Testing the context API](#testing-the-context-api) - [Creating Custom Scroll Actions with Svelte](#creating-custom-scroll-actions-with-svelte) - [Debugging Svelte Apps in VS Code](#debugging-svelte-apps-in-vs-code) - [Avoiding Memory Leaks with Svelte](#avoiding-memory-leaks-with-svelte) @@ -29,6 +34,28 @@ All examples have some variation "with Svelte" appended to them in an attempt to - [Dockerize a Svelte App](#dockerize-a-svelte-app) - [Practical use of Svelte slots with Google Maps](#practical-use-of-svelte-slots-with-google-maps) - [How to make a pre-processor that makes it possible to use PUG/Jade](#how-to-make-a-pre-processor-that-makes-it-possible-to-use-pugjade) +- [Reactivity](#reactivity) + - [Reactive assignments](#reactive-assignments) + - [Top-level variables](#top-level-variables) + - [`each` blocks](#each-blocks) + - [Variables not values](#variables-not-values) + - [Shadowed variables](#shadowed-variables) + - [Reactive Declarations](#reactive-declarations) + - [Defining dependencies](#defining-dependencies) + - [Variable deconstruction](#variable-deconstruction) + - [Hiding values from reactive declarations](#hiding-values-from-reactive-declarations) +- [Stores](#stores) + - [The store contract](#the-store-contract) + - [`store.subscribe`](#storesubscribe) + - [`store.set`](#storeset) + - [Custom stores](#custom-stores) + - [Linked stores](#linked-stores) + - [a custom implementation of the builtin store](#a-custom-implementation-of-the-builtin-store) +- [Server Side Rendering](#server-side-rendering) + - [`svelte.preprocess`](#sveltepreprocess) + - [Markup preprocessors](#markup-preprocessors) + - [Script preprocessors](#script-preprocessors) + - [Style preprocessors](#style-preprocessors) From 42e60e2ccc48e9b614bec39b9428e399d186874b Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:26:07 +0100 Subject: [PATCH 8/9] i give up, doc toc has defeated me --- README.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 10c86e2..7552f3e 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ All examples have some variation "with Svelte" appended to them in an attempt to - [Linked stores](#linked-stores) - [a custom implementation of the builtin store](#a-custom-implementation-of-the-builtin-store) - [Server Side Rendering](#server-side-rendering) - - [`svelte.preprocess`](#sveltepreprocess) + - [svelte.preprocess](#sveltepreprocess) - [Markup preprocessors](#markup-preprocessors) - [Script preprocessors](#script-preprocessors) - [Style preprocessors](#style-preprocessors) @@ -803,14 +803,6 @@ Since we have written custom `set` methods, we are also free to bind to each ind See it in action below. The following example uses the `synced` store to convert between Celsius and Fahrenheit in both directions. -
- -
- *the stuff i actually wrote ends here, this is a fun example that could be included though* ### a custom implementation of the builtin store @@ -851,6 +843,8 @@ Edit: Probably worth mentioning that this is a full writable implementation, onl ## Routing +*some content* + - A map for an app: what is routing - Different approaches - XML-stylee: [svelte-routing](https://github.com/EmilTholin/svelte-routing) @@ -859,6 +853,8 @@ Edit: Probably worth mentioning that this is a full writable implementation, onl ## Server Side Rendering +*some content* + - What is it - What does the API look like - building an SSR component @@ -866,7 +862,6 @@ Edit: Probably worth mentioning that this is a full writable implementation, onl - building a simple express-based SSR server thing - putting it all together - ## Preprocessors > This article references `svelte.preprocess` throughout but you may be more familiar with the `preprocess` option of `svelte-loader` or `rollup-plugin-svelte`. This `preprocess` option calls `svelte.preprocess` internally. The bundler plugin gives you easy access to it, so you don't need to transform your components before compilation manually. @@ -875,7 +870,7 @@ The Svelte compiler expects all components it receives to be valid Svelte syntax With `svelte.preprocess` you have a great deal of flexibility in how you write your components while ensuring that the Svelte compiler receives a plain component. -### `svelte.preprocess` +### svelte.preprocess Svelte's `preprocess` method expects an object or an array of objects with one or more of `markup`, `script`, and `style` properties, each being a function receiving the source code as an argument. The preprocessors run in this order. From 4f26fcb084edd1e7277ac34cc3e55b6d0ea03d58 Mon Sep 17 00:00:00 2001 From: pngwn Date: Sat, 4 Apr 2020 19:28:05 +0100 Subject: [PATCH 9/9] i doctocced the issue templates --- .github/ISSUE_TEMPLATE/ask-a-question.md | 8 -------- .github/ISSUE_TEMPLATE/propose-recipe.md | 8 -------- 2 files changed, 16 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/ask-a-question.md b/.github/ISSUE_TEMPLATE/ask-a-question.md index 674d827..33c1216 100644 --- a/.github/ISSUE_TEMPLATE/ask-a-question.md +++ b/.github/ISSUE_TEMPLATE/ask-a-question.md @@ -1,11 +1,3 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [Ask A Question](#ask-a-question) - - - --- name: Ask a Question about: Ask a question about a Recipe, get answers! We may ask you to contribute a diff --git a/.github/ISSUE_TEMPLATE/propose-recipe.md b/.github/ISSUE_TEMPLATE/propose-recipe.md index ba176dd..386694b 100644 --- a/.github/ISSUE_TEMPLATE/propose-recipe.md +++ b/.github/ISSUE_TEMPLATE/propose-recipe.md @@ -1,11 +1,3 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [Proposed Recipe](#proposed-recipe) - - - --- name: Propose Recipe about: Suggest a Recipe to Add