zauberzeug / nicegui

Create web-based user interfaces with Python. The nice way.
https://nicegui.io
MIT License
8.9k stars 538 forks source link

Can't use import statement in custom Vue components(sfc) #1198

Closed DaelonSuzuka closed 10 months ago

DaelonSuzuka commented 1 year ago

Description

I want to write a Vue Single-File Component (SFC). There are several Vue features I want to use that have to be imported.

The Vue documentation very clearly prescribes using import statements inside the <script> block in the SFC.

The Quasar docs also very clearly use imports. Here's a link to an SFC example from Quasar's documentation:

https://github.com/quasarframework/quasar/blob/dev/docs/src/examples/QTable/PopupEditing.vue#L48

I combine that .vue file with these python files:

table.py

from nicegui.element import Element

class Table(Element, component='table.vue'):
    def __init__(self) -> None:
        super().__init__()

main.py

from nicegui import ui
from table import Table

@ui.page('/')
def index():
    ui.label('hello')

ui.run(port=8081)

When I try to load that page in the browser, I get Uncaught SyntaxError: missing ) after argument list. This error points to the following generated code (only the first line is important):

index.html

//                                                            v---------------v this is not correct
var table = app.component('nicegui-table', {template:'#tpl-t', ref } from 'vue'

const columns = [
  {
    name: 'name',
    required: true,
    label: 'Dessert (100g serving)',
    align: 'left',
    field: row => row.name,
    format: val => `${val}`,
    sortable: true
  },
  { name: 'calories', align: 'center', label: 'Calories', field: 'calories', sortable: true },
  { name: 'fat', label: 'Fat (g)', field: 'fat', sortable: true, style: 'width: 10px' },
  { name: 'carbs', label: 'Carbs (g)', field: 'carbs' },
  { name: 'protein', label: 'Protein (g)', field: 'protein' },
  { name: 'sodium', label: 'Sodium (mg)', field: 'sodium' },
  { name: 'calcium', label: 'Calcium (%)', field: 'calcium', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) },
  { name: 'iron', label: 'Iron (%)', field: 'iron', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) }
]

const rows = [
  {
    name: 'Frozen Yogurt',
    calories: 159,
    fat: 6.0,
    carbs: 24,
    protein: 4.0,
    sodium: 87,
    calcium: '14%',
    iron: '1%'
  },
  {
    name: 'Ice cream sandwich',
    calories: 237,
    fat: 9.0,
    carbs: 37,
    protein: 4.3,
    sodium: 129,
    calcium: '8%',
    iron: '1%'
  }
]

export default {
  setup () {
    return {
      columns,
      rows: ref(rows)
    }
  }
});

I don't fully understand how index.html is being generated, but I believe I've tracked this block of code to here: https://github.com/zauberzeug/nicegui/blob/main/nicegui/dependencies.py#L65.

vbuild.VBuild() is from another package, and it looks (to me) like the root cause of this problem is how vbuild is parsing the .vue file?

I know you guys don't control vbuild, but this issue caused me several days of confusion as I tried to use official examples from Vue and Quasar docs to build a custom component in NiceGUI and nothing worked for vague reasons.

I did finally get a .vue SFC working with no import statements, so I'm not blocked by this today, but imports will be required if I want to use many of Vue's features in the future.

falkoschindler commented 1 year ago

Hi @DaelonSuzuka, thanks for reporting this problem!

We are very sorry for the trouble you went through. We have used SFCs only sparingly so far, therefore we didn't noticed this shortcoming of vbuild.

After #1187 this is already the second issue related to vbuild this week and I'm wondering how to proceed. Pulling the source code into our own repo and fixing the deprecation warning is one thing. But repairing import statements sounds far more complicated.

Of course, we could fork the repo, study and update the Python code, fix the most pressing bugs, setup a proper testing and deployment system with GitHub actions and finally release a separate PyPI package as a successor for vbuild. Well, before doing that, we could ask @manatlan for admin access to the vbuild repo.

falkoschindler commented 1 year ago

I just created a new issue over at vbuild to discuss its further development: https://github.com/manatlan/vbuild/issues/11

DaelonSuzuka commented 1 year ago

sorry for the trouble

I'm sorry to have thrown this much extra work on the pile! Hopefully my post didn't sound too aggressive, because NiceGUI has been absolutely fantastic overall and very, very productive, so losing a couple of days to this issue really isn't that bad.

I suppose I could have followed NiceGUI's examples and written my component as a .js file, but I really wanted to use the Vue extension to get syntax highlighting and autocompletion in the template/html as well as the javascript.

Fun side note I hate writing html in strings so much that I actually started writing a NiceGUI VSCode extension to make it a little nicer to add slots to things: ![EpicPen_T0UNeG7o93](https://github.com/zauberzeug/nicegui/assets/18042232/96cbd838-4df0-4ba6-b2b2-07c2418f3f4e)
falkoschindler commented 1 year ago

Oh wow! That side note looks awesome! I'm very much looking forward to seeing more of it once it's ready. 🤩

No, your post didn't sound aggressive. But this kind of frustration is exactly what NiceGUI is trying to avoid. Sure, that's not always possible once a project reaches a certain complexity. And the overall feedback is great. Thanks for that! 🙂

falkoschindler commented 1 year ago

I just noticed that vbuild doesn't support Vue 3 (https://github.com/manatlan/vbuild/issues/8). And (according to ChatGPT) the code in question is Vue 3:

The line import { ref } from 'vue' is a Vue 3 concept. This is part of the Composition API introduced in Vue 3. The ref function is used to create a reactive reference to a value.

So I guess we can't do anything about this issue - besides re-implementing vbuild for Vue 3, which we don't have the knowledge and resources for.

DaelonSuzuka commented 1 year ago

Good to know. Maybe I'll take a look at it.