reflex icon indicating copy to clipboard operation
reflex copied to clipboard

When Wrapping React, how to specify generated `import` style(Tag) in nextjs?

Open forhonourlx opened this issue 3 years ago β€’ 6 comments

Describe the bug Hi Pynecone Team I am trying to wrap echarts-for-react, a beautiful and fully controlled graphing npm into pynecone app. In ./.web/pages/index.js, auto generated code is import {ReactECharts} from "echarts-for-react". To run nextjs, I need import ReactECharts from "echarts-for-react". How to specify that style of import? And more, if old style var moment = require('moment') is needed, how to specify tag? Thank you inadvance.

To Reproduce Steps to reproduce the behavior: echarts: https://echarts.apache.org/examples/en/index.html react wrap: https://github.com/hustcc/echarts-for-react

pcconfig.py:

import pynecone as pc
config = pc.Config(
    app_name="TEST_Echarts",
    db_url="sqlite:///pynecone.db",
    env=pc.Env.DEV,
    frontend_packages=["echarts","echarts-for-react"],
)

TEST_Echarts.py:

from pcconfig import config
import pynecone as pc
docs_url = "https://pynecone.io/docs/getting-started/introduction"
filename = f"{config.app_name}/{config.app_name}.py"

class ReactECharts(pc.Component):
    library = "echarts-for-react"
    tag = "ReactECharts"
    option: pc.Var[dict]

echarts_react = ReactECharts.create

class State(pc.State):
    """The app state."""
    pass

ec_option = {
    'xAxis': {
      'type': 'category',
      'data': ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    },
    'yAxis': {
      'type': 'value',
    },
    'series': [
      {
        'data': [820, 932, 901, 934, 1290, 1330, 1320],
        'type': 'line',
        'smooth': True,
      },
    ],
    'tooltip': {
      'trigger': 'axis',
    },
}

def index():
    return pc.center(
        pc.vstack(
            pc.heading("Welcome to Pynecone!", font_size="2em"),
            pc.container(
              pc.center(pc.text("box here"),),
              echarts_react(option=ec_option,),
              bg="deepskyblue",
              width="100%",
              padding=5,
            ),
            spacing="1.5em",
            font_size="2em",
        ),
        padding_top="10%",
    )

# Add state and page to the app.
app = pc.App(state=State)
app.add_page(index)
app.compile()

./.web/pages/index.js:

import {useEffect, useState} from "react"
import {useRouter} from "next/router"
import {E, updateState} from "/utils/state"
import "focus-visible/dist/focus-visible"
import {Center, Container, Heading, Text, VStack} from "@chakra-ui/react"
import {ReactECharts} from "echarts-for-react"//Error
import NextHead from "next/head"

const EVENT = "http://localhost:8000/event"
export default function Component() {
const [state, setState] = useState({"color": "#db114b", "events": [{"name": "state.hydrate"}]})
const [result, setResult] = useState({"state": null, "events": [], "processing": false})
const router = useRouter()
const Event = events => setState({
  ...state,
  events: [...state.events, ...events],
})
useEffect(() => {
  const update = async () => {
    if (result.state != null) {
      setState({
        ...result.state,
        events: [...state.events, ...result.events],
      })
      setResult({
        state: null,
        events: [],
        processing: false,
      })
    }
    await updateState(state, result, setResult, EVENT, router)
  }
  update()
})
return (
<Center sx={{"paddingTop": "10%"}}>
<VStack spacing="1.5em"
sx={{"fontSize": "2em"}}>
<Heading sx={{"fontSize": "2em"}}>
{`Welcome to Pynecone!`}</Heading>
<Container sx={{"bg": "deepskyblue", "width": "100%", "padding": 5}}>
<Center>
<Text>
{`box here`}</Text></Center>
<ReactECharts option={{"xAxis": {"type": "category", "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]}, "yAxis": {"type": "value"}, "series": [{"data": [820, 932, 901, 934, 1290, 1330, 1320], "type": "line", "smooth": true}], "tooltip": {"trigger": "axis"}}}/></Container></VStack>
<NextHead>
<title>{`Pynecone App`}</title>
<meta content="A Pynecone app."
name="description"/>
<meta property="og:image"
content="favicon.ico"/></NextHead></Center>
)
}

** Specifics (please complete the following information):**

  • Python Version: 3.10
  • Pynecone Version: 0.1.11
  • OS: WSL2
  • Browser (Optional):Chrome

forhonourlx avatar Jan 01 '23 15:01 forhonourlx

Hey, thanks for taking this on!

So to do the default import, you should set the tag to the same (title-case) version of the library.

tag = "EchartsForReact"

Since it's the default import, the name shouldn't matter and it should compile out as <EchartsForReact> tags.

You can also specify additional imports using the _get_imports function, see here for an example.

This all uses the import syntax. If you want to add additional code to be compiled in (like a require statement), you can use the _get_custom_code method and the code returned by that will be included at the top of each page that the component is imported. See here for an example.

Let me know if that works for you!

picklelo avatar Jan 01 '23 18:01 picklelo

Hi @picklelo , Following your instruction, after TEST_Echarts.py is modified with:

class ReactECharts(pc.Component):
    library = "echarts-for-react"
    tag = "ReactECharts"
    option: pc.Var[dict]

    def _get_imports(self):
        return {}

    def _get_custom_code(self) -> str:
        return f'import {self.tag} from "{self.library}"'

./.web/pages/index.js generated import ReactECharts from "echarts-for-react" inplace, and works properly.

Anyhow, how to use get_imports directly to fix above problem?

forhonourlx avatar Jan 02 '23 16:01 forhonourlx

Ah I see so basically the brackets in your import are the problem. This in interesting because the wrapping react example output doesn't have brackets see here https://pynecone.io/docs/advanced-guide/wrapping-react.

If you need to insert a specific line such as var moment = require('moment') you can do this as so.

Let me know if this helps. Im going to try your branch and see if I can reproduce this

class ReactECharts(pc.Component):
    library = "echarts-for-react"
    tag = "ReactECharts"
    option: pc.Var[dict]

    def _get_custom_code(self) -> str:
        return f"'var moment = require('moment')"

Alek99 avatar Jan 03 '23 08:01 Alek99

Ah your right I was able to reproduce this on mine with the brackets. Looking into this.

We also have a discord it may be easier for quick communication for debugging this @picklelo can send invite to this.

Alek99 avatar Jan 03 '23 08:01 Alek99

Thanks. Could you please invite my dicord: [email protected]

forhonourlx avatar Jan 08 '23 14:01 forhonourlx

We just added the discord link to the bottom of the README

picklelo avatar Jan 08 '23 22:01 picklelo