1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

vweb: document live reload

This commit is contained in:
Alexander Medvednikov 2023-07-08 19:29:11 +03:00
parent 4f518c2850
commit 5355c67ebe
2 changed files with 36 additions and 25 deletions

View File

@ -86,6 +86,10 @@ pub enum FormatDelimiter {
no_delimiter no_delimiter
} }
pub fn Time.new(t Time) Time {
return new_time(t)
}
// smonth returns month name abbreviation. // smonth returns month name abbreviation.
pub fn (t Time) smonth() string { pub fn (t Time) smonth() string {
if t.month <= 0 || t.month > 12 { if t.month <= 0 || t.month > 12 {

View File

@ -7,7 +7,14 @@ The [gitly](https://gitly.org/) site is based on vweb.
**_Some features may not be complete, and have some bugs._** **_Some features may not be complete, and have some bugs._**
## Quick Start ## Quick Start
Just run **`v new <name> web`** in your terminal Just run **`v new <name> web`** in your terminal.
Run your vweb app with a live reload via `v -d vweb_livereload watch run .`
Now modifying any file in your web app (whether it's a .v file with the backend logic
or a compiled .html template file) will result in an instant refresh of your app
in the browser. No need to quit the app, rebuild it, and refresh the page in the browser!
## Features ## Features
@ -253,7 +260,7 @@ pub fn (mut app App) controller_get_user_by_id() vweb.Result {
``` ```
#### - Host #### - Host
To restrict an endpoint to a specific host, you can use the `host` attribute To restrict an endpoint to a specific host, you can use the `host` attribute
followed by a colon `:` and the host name. You can test the Host feature locally followed by a colon `:` and the host name. You can test the Host feature locally
by adding a host to the "hosts" file of your device. by adding a host to the "hosts" file of your device.
**Example:** **Example:**
@ -293,10 +300,10 @@ pub fn (mut app App) before_request() {
} }
``` ```
Middleware functions can be passed directly when creating an App instance and is Middleware functions can be passed directly when creating an App instance and is
executed when the url starts with the defined key. executed when the url starts with the defined key.
In the following example, if a user navigates to `/path/to/test` the middleware In the following example, if a user navigates to `/path/to/test` the middleware
is executed in the following order: `middleware_func`, `other_func`, `global_middleware`. is executed in the following order: `middleware_func`, `other_func`, `global_middleware`.
The middleware is executed in the same order as they are defined and if any function in The middleware is executed in the same order as they are defined and if any function in
the chain returns `false` the propogation is stopped. the chain returns `false` the propogation is stopped.
@ -342,7 +349,7 @@ fn global_middleware(mut ctx vweb.Context) bool {
} }
``` ```
Middleware functions will be of type `vweb.Middleware` and are not methods of App, Middleware functions will be of type `vweb.Middleware` and are not methods of App,
so they could also be imported from other modules. so they could also be imported from other modules.
```v ignore ```v ignore
pub type Middleware = fn (mut Context) bool pub type Middleware = fn (mut Context) bool
@ -374,7 +381,7 @@ The middleware is executed in the following order:
3. The middleware in the `[middleware]` attribute 3. The middleware in the `[middleware]` attribute
If any function of step 2 or 3 returns `false` the middleware functions that would If any function of step 2 or 3 returns `false` the middleware functions that would
come after it are not executed and the app handler will also not be executed. You come after it are not executed and the app handler will also not be executed. You
can think of it as a chain. can think of it as a chain.
### Context values ### Context values
@ -435,7 +442,7 @@ We get this key in `index` and display it to the user if the `'user'` key exists
#### Changing Context values #### Changing Context values
By default context values are immutable when retrieved with `get_value`. If you want to By default context values are immutable when retrieved with `get_value`. If you want to
change the value later you have to set it again with `set_value`. change the value later you have to set it again with `set_value`.
**Example:** **Example:**
@ -494,7 +501,7 @@ pub fn (mut app App) with_auth() bool {
``` ```
### Fallback route ### Fallback route
You can implement a fallback `not_found` route that is called when a request is made and no You can implement a fallback `not_found` route that is called when a request is made and no
matching route is found. matching route is found.
**Example:** **Example:**
@ -507,7 +514,7 @@ pub fn (mut app App) not_found() vweb.Result {
``` ```
### Databases ### Databases
The `db` field in a vweb app is reserved for database connections. The connection is The `db` field in a vweb app is reserved for database connections. The connection is
copied to each new request. copied to each new request.
**Example:** **Example:**
@ -536,7 +543,7 @@ fn main() {
### Multithreading ### Multithreading
By default, a vweb app is multithreaded, that means that multiple requests can By default, a vweb app is multithreaded, that means that multiple requests can
be handled in parallel by using multiple CPU's: a worker pool. You can be handled in parallel by using multiple CPU's: a worker pool. You can
change the number of workers (maximum allowed threads) by altering the `nr_workers` change the number of workers (maximum allowed threads) by altering the `nr_workers`
option. The default behaviour is to use the maximum number of jobs (cores in most cases). option. The default behaviour is to use the maximum number of jobs (cores in most cases).
@ -560,7 +567,7 @@ To resolve this issue, you can use the vweb's built-in database pool. The databa
will keep a number of connections open when the app is started and each worker is will keep a number of connections open when the app is started and each worker is
assigned its own connection. assigned its own connection.
Let's look how we can improve our previous example with database pooling and using a Let's look how we can improve our previous example with database pooling and using a
postgresql server instead. postgresql server instead.
**Example:** **Example:**
@ -593,14 +600,14 @@ fn main() {
} }
``` ```
If you don't use the default number of workers (`nr_workers`) you have to change If you don't use the default number of workers (`nr_workers`) you have to change
it to the same number in `vweb.run_at` as in `vweb.database_pool` it to the same number in `vweb.run_at` as in `vweb.database_pool`
### Extending the App struct with `[vweb_global]` ### Extending the App struct with `[vweb_global]`
You can change your `App` struct however you like, but there are some things you You can change your `App` struct however you like, but there are some things you
have to keep in mind. Under the hood at each request a new instance of `App` is have to keep in mind. Under the hood at each request a new instance of `App` is
constructed, and all fields are re-initialized with their default type values, constructed, and all fields are re-initialized with their default type values,
except for the `db` field. except for the `db` field.
This behaviour ensures that each request is treated equally and in the same context, but This behaviour ensures that each request is treated equally and in the same context, but
problems arise when we want to provide more context than just the default `vweb.Context`. problems arise when we want to provide more context than just the default `vweb.Context`.
@ -628,8 +635,8 @@ fn (mut app App) index() vweb.Result {
} }
``` ```
When you visit `localhost:8080/` you would expect to see the text When you visit `localhost:8080/` you would expect to see the text
`"My secret is: my secret"`, but instead there is only the text `"My secret is: my secret"`, but instead there is only the text
`"My secret is: "`. This is because of the way vweb works. We can override the default `"My secret is: "`. This is because of the way vweb works. We can override the default
behaviour by adding the attribute `[vweb_global]` to the `secret` field. behaviour by adding the attribute `[vweb_global]` to the `secret` field.
@ -647,8 +654,8 @@ Now if you visit `localhost:8080/` you see the text `"My secret is: my secret"`.
> next request. You can use shared fields for this. > next request. You can use shared fields for this.
### Shared Objects across requests ### Shared Objects across requests
We saw in the previous section that we can persist data across multiple requests, We saw in the previous section that we can persist data across multiple requests,
but what if we want to be able to mutate the data? Since vweb works with threads, but what if we want to be able to mutate the data? Since vweb works with threads,
we have to use `shared` fields. we have to use `shared` fields.
Let's see how we can add a visitor counter to our `App`. Let's see how we can add a visitor counter to our `App`.
@ -700,7 +707,7 @@ requests the next requests will have to wait for the lock to be released.
It is best practice to limit the use of shared objects as much as possible. It is best practice to limit the use of shared objects as much as possible.
### Controllers ### Controllers
Controllers can be used to split up app logic so you are able to have one struct Controllers can be used to split up app logic so you are able to have one struct
per `"/"`. E.g. a struct `Admin` for urls starting with `"/admin"` and a struct `Foo` per `"/"`. E.g. a struct `Admin` for urls starting with `"/admin"` and a struct `Foo`
for urls starting with `"/foo"` for urls starting with `"/foo"`
@ -734,9 +741,9 @@ fn main() {
} }
``` ```
You can do everything with a controller struct as with a regular `App` struct. You can do everything with a controller struct as with a regular `App` struct.
The only difference being is that only the main app that is being passed to `vweb.run` The only difference being is that only the main app that is being passed to `vweb.run`
is able to have controllers. If you add `vweb.Controller` on a controller struct it is able to have controllers. If you add `vweb.Controller` on a controller struct it
will simply be ignored. will simply be ignored.
#### Routing #### Routing
@ -749,10 +756,10 @@ pub fn (mut app Admin) path vweb.Result {
} }
``` ```
When we created the controller with `vweb.controller('/admin', &Admin{})` we told When we created the controller with `vweb.controller('/admin', &Admin{})` we told
vweb that the namespace of that controller is `"/admin"` so in this example we would vweb that the namespace of that controller is `"/admin"` so in this example we would
see the text `"Admin"` if we navigate to the url `"/admin/path"`. see the text `"Admin"` if we navigate to the url `"/admin/path"`.
Vweb doesn't support fallback routes or duplicate routes, so if we add the following Vweb doesn't support fallback routes or duplicate routes, so if we add the following
route to the example the code will produce an error. route to the example the code will produce an error.
```v ignore ```v ignore
@ -1198,5 +1205,5 @@ pub fn (mut app App) error() vweb.Result {
``` ```
# Cross-Site Request Forgery (CSRF) protection # Cross-Site Request Forgery (CSRF) protection
Vweb has built-in csrf protection. Go to the [csrf module](csrf/) to learn how Vweb has built-in csrf protection. Go to the [csrf module](csrf/) to learn how
you can protect your app against CSRF. you can protect your app against CSRF.