Skip to content

vcreate: migrate vweb model to veb#26745

Merged
JalonSolov merged 2 commits into
vlang:masterfrom
emerikaji:migrate_vweb_project_to_veb
Mar 18, 2026
Merged

vcreate: migrate vweb model to veb#26745
JalonSolov merged 2 commits into
vlang:masterfrom
emerikaji:migrate_vweb_project_to_veb

Conversation

@emerikaji

Copy link
Copy Markdown
Contributor

See issue #24270 for context.

This PR migrates the example project used as a demo for the vweb library into the veb library.

The structure has been slightly altered to follow more consistent web development standards, and align more closely with the code shown in the vdoc. However, functionality has been kept identical.

As a side note, it would perhaps be useful in the future to have a better system for the creation of such example projects, rather than pasting the full code into one file. For simplicity, this is fine for now.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54cc8f6af7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread cmd/tools/vcreate/project_model_web.v Outdated
defer { db.close() or { panic(err) } }

mut app := &App{ db: db }
app.handle_static('static', true)!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resolve static dir independently of process cwd

The generated main.v now uses app.handle_static('static', true)!, but veb.StaticHandler.handle_static resolves that folder relative to the current working directory. This means the scaffolded app will panic at startup when launched from any other directory (for example via an absolute binary path from a shell/systemd), because static is not found there. The previous template used executable-relative paths, so this is a runtime regression in common deployment scenarios.

Useful? React with 👍 / 👎.

@JalonSolov

Copy link
Copy Markdown
Collaborator

Close/re-open for CI.

@JalonSolov JalonSolov closed this Mar 18, 2026
@JalonSolov JalonSolov reopened this Mar 18, 2026
@JalonSolov

Copy link
Copy Markdown
Collaborator

Need to run v fmt -w on the files.

@emerikaji

Copy link
Copy Markdown
Contributor Author

Need to run v fmt -w on the files.

v fmt seems to have some weirdly inconsistent behavior in this case.

It will sometimes pick single quotes, sometimes double quotes in the content field of the ProjectFiles, and swap all escaped quotation marks in the process.
It doesn't seem to be a matter of length (for instance, products.css gets changed despite its short length) or type of content, but maybe there's something I'm missing. This behavior was already visible on the original version.

Here's an example, this one is changed:

c.files << ProjectFiles{
                path:    os.join_path(base, 'auth_controller.v')
                content: 'module main

import crypto.bcrypt
import crypto.hmac
import encoding.base64
import crypto.sha256
import json

fn (app &App) do_auth(username string, password string) !string {
        users := sql app.db {
                select from User where username == username
        }!
        if users.len == 0 {
                return error(\'user not found\')
        }
        user := users.first()
        if !user.active {
                return error(\'user is not active\')
        }
        bcrypt.compare_hash_and_password(password.bytes(), user.password.bytes()) or {
                return error(\'Failed to auth user, \${err}\')
        }
        return make_token(user)
}

fn (app &App) verify_auth(token string) bool {
        if token == \'\' {
                return false
        }
        secret := \'SECRET_KEY\' // os.getenv(\'SECRET_KEY\')
        token_split := token.split(\'.\')
        signature_mirror := hmac.new(secret.bytes(), \'\${token_split[0]}.\${token_split[1]}\'.bytes(),
                sha256.sum, sha256.block_size).bytestr().bytes()
        signature_from_token := base64.url_decode(token_split[2])
        return hmac.equal(signature_from_token, signature_mirror)
}

fn (app &App) user_auth(token string) !int {
        if !app.verify_auth(token) {
                return error("Invalid token")
        }
        jwt_payload_stringify := base64.url_decode_str(token.split(\'.\')[1])
        jwt_payload := json.decode(JwtPayload, jwt_payload_stringify) or {
                return err
        }
        return jwt_payload.sub.int()
}
'

While this one is not:

c.files << ProjectFiles{
                path:    os.join_path(base, 'user_controller.v')
                content: "module main

import crypto.bcrypt

fn (app &App) add_user(username string, password string) ! {
        hashed_password := bcrypt.generate_from_password(password.bytes(), bcrypt.min_cost)!
        user_model := User{
                username: username
                password: hashed_password
                active: true
        }
        sql app.db {
                insert user_model into User
        }!
}

fn (app &App) get_users() ![]User {
        return sql app.db {
                select from User
        }!
}

fn (app &App) get_user(id int) !User {
        results := sql app.db {
                select from User where id == id
        }!
        if results.len == 0 {
                return error('no results')
        }
        return results[0]
}
"

@JalonSolov

Copy link
Copy Markdown
Collaborator

That first example does look odd.

v fmt is supposed to examine strings, and if they have " in them, change the outer set to ', or if they have ' in them, change the outer set to ".

It should not create strings with ' as the outer set, then \' inside the string. The \$ bits are correct regardless of outer quotes.

Can you manually modify the first example to have " as the outer set, and remove all \ inside the string unless it is before $? And if you do, does it still change things?

@emerikaji

Copy link
Copy Markdown
Contributor Author

That's actually what I did prior to running v fmt again and sending the examples in question. I ran it once using v fmt -w, noticed the quotation mark swaps, corrected them, and ran it again without overwrite this time to check if it behaved in the same way, which it did.

My current assessment is that the clause dictating, if there are " in the string then use ' as the outer, takes priority over the other clause. I believe this is the case as v fmt defaults to ' when no quotation marks are used in the string. This isn't bad behavior, but there should definitely be a way for v fmt to check if there are more ' or " in a given string and choose the outer accordingly to avoid such cases.

I will be pushing the changes soon. This was my fault as this first example had a string with double quotes whereas v fmt employs single quotes.

As a side note, would it be of help if I developed a simple v app/script to convert a v project into a model file like this one?

…iles inside model and on the model file itself
@JalonSolov

JalonSolov commented Mar 18, 2026

Copy link
Copy Markdown
Collaborator

That's basically what v create does... build a project from model files. Those files just happen to be strings in the code.

One change you could make is to extract those strings into separate files (each template project as a separate subdir, perhaps), and use $embed_file() to make them part of the final executable.

That way, you could format them once, then not have to worry about them again, unless the template files themselves change.

@JalonSolov

Copy link
Copy Markdown
Collaborator

Merging what's here... can always do a new PR for changes.

@JalonSolov JalonSolov merged commit 7911944 into vlang:master Mar 18, 2026
29 checks passed
@emerikaji emerikaji deleted the migrate_vweb_project_to_veb branch March 19, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants