Giter Club home page Giter Club logo

startupjs / startupjs Goto Github PK

View Code? Open in Web Editor NEW
105.0 12.0 45.0 231.83 MB

⚡ Universal React Native + Web framework with isomorphic collaborative DB and observables

Home Page: https://startupjs-ui.dev.dmapper.co

JavaScript 61.81% Dockerfile 0.21% Shell 3.24% CSS 0.14% HTML 0.09% Starlark 0.03% Java 0.28% Ruby 0.04% Objective-C 0.28% Stylus 2.84% Swift 0.01% C 0.01% MDX 30.10% TypeScript 0.94%
react sharedb react-native framework nodejs express mongodb react-native-web reactive-programming

startupjs's Introduction

Cover

StartupJS ·

Quickstart   •   Native development   •   IDE support   •   Docs   •   Packages   •   Migration

What is StartupJS?

StartupJS is a full-stack framework that consists of:

Quickstart

Requirements

StartupJS app requires: Node 20.10+, Yarn

Alternatively, you can run everything in Docker, in which case follow Docker development Quick Start. Important to note is that Docker won't allow you to test Android or iOS.

Installation

Warning

StartupJS does not yet support the latest version of React Native.

When creating a new project please specify the 0.72 version:

npx startupjs@latest init myapp --react-native 0.72

If you want to use the latest React Native, install StartupJS Alpha version

  1. Initialize a default ui template project, change myapp to your project name (use lower case):

    npx startupjs@latest init myapp
    
  2. Go into the created project folder and start the web application with:

    yarn start
    
  3. Open http://localhost:3000 and start developing!

Alpha version on Expo (for React Native >=0.73)

  1. Create a new expo app and go into it (change myapp to the name of your app):

    Note: You can use any Expo template you want by specifying the --template option.

    • for npm:

      npx create-expo-app@latest myapp
      
      cd myapp
      
    • for yarn:

      yarn create expo-app myapp
      
      cd myapp
      
      • To use the latest Yarn Berry v4 (recommended), do the following:

        corepack enable && echo 'nodeLinker: node-modules' > .yarnrc.yml && corepack use yarn@4
        

        Warning: If you are on Mac, you might first need to install corepack separately with:

        brew install corepack
        
  2. Install startupjs into your app:

    npm init startupjs@next
    
  3. Wrap your root component into <StartupjsProvider> from startupjs (when using expo-router it's in app/_layout.tsx):

    import { StartupjsProvider } from 'startupjs'
    // ...
    return (
      <StartupjsProvider>
        ...
      </StartupjsProvider>
    )
  4. Start expo app with npm start or yarn start

  5. If Fast Refresh (hot reloading) is not working (this might be the case if you created a bare expo project), add import '@expo/metro-runtime' to the top of your entry file.

Native Development (iOS and Android)

Requiremens

Follow the React Native guide to setup everything. StartupJS uses native modules, so you have to follow React Native CLI Quickstart, not the Expo guide.

How to run StartupJS on native

yarn start actually combines 2 commands together: yarn server and yarn web.

In order to develop your app on mobile, you'll have to open a bunch of tabs anyways, so it makes sense to also run server and web separately instead of using the yarn start.

Here is the list of commands to run all platforms at the same time:

  1. Start server (required) in a separate terminal tab

    yarn server
    
  2. Start web (optional) in a separate terminal tab

    yarn web
    
  3. Start metro (required for Android and/or iOS) in a separate terminal tab

    yarn metro
    
  4. Run android (optional) in a separate terminal tab

    yarn android
    
  5. Run ios (optional) in a separate terminal tab

    yarn ios
    

IDE configuration

Visual Studio Code

Step 1: Add support for PUG syntax highlighting

  1. Install extension vscode-react-pug
  2. Restart VS Code

Step 2: Add support for ESLint errors highlighting

  1. Install extension ESLint
  2. Restart VS Code

Atom

Step 1: Add support for PUG syntax highlighting

  1. Install packages language-babel and language-pug
  2. Open settings of language-babel in atom
  3. Find the field under "JavaScript Tagged Template Literal Grammar Extensions"
  4. Enter: pug:source.pug
  5. Go to Core settings of atom.
  6. Uncheck Use Tree Sitter Parsers
  7. Restart Atom

Step 2: Add support for ESLint errors highlighting

  1. Install package linter-eslint
  2. Restart Atom

Documentation

The main things you'll need to know to get started with StartupJS are:

  1. React Native
  2. Racer's Model. You only need to read the MODELS section, ignore everything else.
  3. React hooks for Model
  4. StartupJS UI Components

Before launching your app to production you are strongly encouraged to implement:

  1. Security

For additional documentation on each StartupJS package see the according readme

Advanced

To gain further deep knowledge of StartupJS stack you'll need get familiar with the following technologies it's built on:

  1. React and/or react-native-web for the Web-frontend.
  2. React Native for the Native-frontend (iOS, Android, etc.).
  3. Pug which is used besides JSX for templating.
  4. Stylus which is used besides CSS for stylesheets.
  5. React-ShareDB:
    • A ShareDB real-time collaborative database integration into React.
    • Allows to sync data between your local state (similar to Redux) and the DB.
    • Brings in collaboration functionality similar to Google Docs, where multiple users can edit the same data simultaneously.
    • Uses WebSockets to send micro-patches to and from the server whenever there are any changes to the data you are subscribed to.
    • Uses observables to automatically rerender the data in React, similar to MobX.
  6. Model based on Racer with an ability to create custom ORM methods.
  7. React Router for routing and navigation with an ability to separate your frontend into multiple frontent mircoservices (e.g. main and admin)
  8. Node.js and Express for the backend.
  9. MongoDB for the database.
  10. Redis for the pub/sub (required by ShareDB) and locking functionality.
  11. Code Quality control tools:

Sub-Packages Documentation

Official App Templates

The following templates are available:

  1. simple
  2. routing - plugs in @startupjs/app which provides a react-router routing implementation
  3. ui (default) - plugs in routing and @startupjs/ui

By default init creates a project using the feature-rich ui template.

To use another template specify the -t option:

npx startupjs init myapp -t simple

To create a new project using an alpha version of startupjs, append @next to the startupjs itself:

npx startupjs@next init myapp

Each template initializes on top of a default react-native init application.

If you want to use an RC version (next) of react-native or a specific version like 0.72, specify it using the --react-native option:

npx startupjs init myapp --react-native next

Docker development Quick Start

Alternatively you can run a docker development image which has node, yarn, mongo and redis already built in. You only need docker for this. And it works everywhere -- Windows, MacOS, Linux.

Keep in mind though that since docker uses its own driver to mount folders, performance (especially when installing modules) might be considerably slower compared to the native installation when working with the large amount of files.

  1. Initialize a new ui boilerplate project. Change myapp at the end to your project name (use lower case).

    docker run --rm -it -v ${PWD}:/ws:delegated startupjs/dev init myapp
    
  2. Go into the created project folder. Then run the development docker container with:

    ./docker
    
  3. While inside the running container, start your app with:

    yarn start
    
  4. Open http://localhost:3000 and start developing!

  5. When you want to open an additional terminal window, you can quickly exec into the running container using:

    ./docker exec
    

Version migration guides

The following guides are available to assist with migration to new major versions of StartupJS:

Security

StartupJS server is designed to be secure by default.

For the sake of simplifying quick prototyping, a new project you create with startupjs init will have security mechanisms turned off.

You are strongly encouraged to implement security for your project as early as possible by removing secure: false flag from the server initialization in your server/index.js file.

There are 3 types of security mechanisms you must implement:

If you want to work on their implementation one by one, you can keep the secure: false flag and only add the ones you want to implement by specifying the following flags:

accessControl: true,
serverAggregate: true,
validateSchema: true

NOTE: All 3 mechanisms are integrated for their simpler use into the ORM system. We are working on a guide on how to use them with the ORM. If you want help properly integrating it into your production project, please file an issue or contact cray0000 directly via email.

Contributing & Troubleshooting

See CONTRIBUTING.md

License

MIT

© Pavel Zhukov

startupjs's People

Contributors

ablaev-rs avatar ablaevrs avatar altxis avatar asiyekk avatar cray0000 avatar dependabot[bot] avatar fcbvirus0k avatar gdancerx avatar katamoritoka avatar lupenq avatar maestrosc avatar narimandev avatar okwergot avatar olvipi avatar pla1d3 avatar pturchik avatar pvturchik avatar rabbitabyss avatar raj793 avatar shir-dm avatar simonz-git avatar ssstelsss avatar tarlord avatar tohellandback avatar vedadeepta avatar vladagurets avatar vmakhaev avatar yska avatar zag2art avatar zheoreh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

startupjs's Issues

Add additional convenience and layout attributes to `Div`

Div is our alternative to material ui's Box -- a universal container component which is used as the base for most other UI components in our libraries and in end-user projects.

We should treat it as such, people are used to having this kind of a base mega-component.

One of the improvements I see is:

  • embed Row functionality into Div and deprecate Row completely:

    Div(row align='center' vAlign='center')

  • Div(row) api of align and vAlign to always have magic values depending on whether it's row or not:

    • for align -- always have correctly behaving left, center, right
    • for vAlign -- always have correctly behaving top, center, bottom

Refactor @startupjs/ui from PropTypes to TypeScript

  • refactor @startupjs/ui to TypeScript
  • update docs to parse TypeScript interfaces of the components to generate props table for Sandbox. This should include parsing additional comments for each prop in jsdoc format, like @default and the description. Look how other styleguide libraries do it, like storybook and competitors.

Use Expo by default in startupjs project

  • change the npx startupjs init command to generate an Expo project
  • update @startupjs/cli commands for yarn metro, yarn ios, yarn android (and any others affected) to instead run stuff through expo
  • expo might have has some specific way to configure Metro transformers and/or babel plugins through its own config. If yes then specify it accordingly.
  • refactor @startupjs/ui, @startupjs/app (and any others affected) to only use native libraries which are built in into Expo
  • test and document the process of adding new (not baked into expo) native modules into the app. Start research on this from this doc - Add custom native code

Fix rerenders

components are always re-rendered due to of styles

Refactor from `nconf` to `.env`

  • refactor server from conf to dotenv which puts everything into process.env.*
  • env vars which should be piped to the client must start with the prefix PUBLIC_
  • preprocess process.env in the frontend code by adding an import to the magic file which will be created during compilation:
const { SESSION_SECRET } = process.env

// v v v

import ENV from 'startupjs/env'
const { SESSION_SECRET } = ENV

where startupjs/env exports a Proxy:

import ENV from './startupjs.env.virtual.js'

export default new Proxy(ENV, {
  get (target, key) {
    return ENV[key] ?? globalThis.process?.env?.[key]
  },
  has (target, key) {
    return !!(ENV[key] ?? globalThis.process?.env?.[key])
  }
})

[e2e] Throws error when launching tests in ios simulator

npx startupjs test --init - OK
npx startupjs test --build - BUILD SUCCESSFUL in 2m 20s
npx startupjs test --ios - throws the error

[T]  FAIL  e2e/firstTest.e2e.js
[T]   ● Test suite failed to run
[T]
[T]     TypeError: Class extends value #<Object> is not a constructor or null
[T]
[T]       at Object.<anonymous> (node_modules/detox/runners/jest-circus/environment.js:23:38)
[T]       at Object.<anonymous> (node_modules/detox/runners/jest-circus/index.js:4:32)
[T]
[T] detox[52773] ERROR: [cli.js] Command failed: jest --config /Users/ovvn/work/myapp/node_modules/@startupjs/e2e/config.js --testNamePattern '^((?!:android:).)*$' --maxWorkers 1 e2e

As suggested here https://stackoverflow.com/questions/72128834/detox-jest-test-suite-failed-to-run-typeerror-class-extends-value-object-is changed jest's version to 27.0.1 but it also throws with more errors:

[T] detox[44312] ERROR: [EXEC_FAIL, #2] "/usr/bin/xcrun simctl terminate 27C3EF20-94DD-4C56-AB94-477C6D5DC886 org.reactjs.native.example.myapp" failed with error = ChildProcessError: Command failed: /usr/bin/xcrun simctl terminate 27C3EF20-94DD-4C56-AB94-477C6D5DC886 org.reactjs.native.example.myapp
[T] An error was encountered processing the command (domain=NSPOSIXErrorDomain, code=3):
[T] The operation couldn’t be completed. found nothing to terminate
[T] found nothing to terminate
[T]  `/usr/bin/xcrun simctl terminate 27C3EF20-94DD-4C56-AB94-477C6D5DC886 org.reactjs.native.example.myapp` (exited with error code 3) (code=3), stdout and stderr:
[T]
[T] detox[44312] ERROR: [EXEC_FAIL, #2]
[T] detox[44312] ERROR: [EXEC_FAIL, #2] An error was encountered processing the command (domain=NSPOSIXErrorDomain, code=3):
[T] The operation couldn’t be completed. found nothing to terminate
[T] found nothing to terminate
[T]
[T] detox[44312] ERROR: Command failed: /usr/bin/xcrun simctl terminate 27C3EF20-94DD-4C56-AB94-477C6D5DC886 org.reactjs.native.example.myapp
[T] An error was encountered processing the command (domain=NSPOSIXErrorDomain, code=3):
[T] The operation couldn’t be completed. found nothing to terminate
[T] found nothing to terminate
[T]  `/usr/bin/xcrun simctl terminate 27C3EF20-94DD-4C56-AB94-477C6D5DC886 org.reactjs.native.example.myapp` (exited with error code 3)
[T] detox[44312] INFO:  Example is assigned to undefined
[T] detox[44312] INFO:  Example: should have welcome screen
[T] detox[44312] INFO:  Example: should have welcome screen [SKIPPED]
[T] detox[44312] INFO:  Example: should show hello screen after tap
[T] detox[44312] INFO:  Example: should show hello screen after tap [SKIPPED]
[T] detox[44312] INFO:  Example: should show world screen after tap
[T] detox[44312] INFO:  Example: should show world screen after tap [SKIPPED]
[T]
[T] detox[44312] ERROR: at node:internal/process/warning:50:3
[T]  (node:44312) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
[T] (Use `node --trace-warnings ...` to show where the warning was created)
[T] detox[44312] ERROR: at node:internal/process/warning:50:3
[T]  (node:44312) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
[T] detox[44312] ERROR: at node:internal/process/warning:50:3
[T]  (node:44312) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
[T] detox[44312] ERROR: at node:internal/process/warning:50:3
[T]  (node:44312) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
[T] detox[44312] ERROR: at node:internal/process/warning:50:3
[T]  (node:44312) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
[T] detox[44312] ERROR: at node:internal/process/warning:50:3
[T]  (node:44312) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
[T] detox[44311] ERROR: [cli.js] Command failed: jest --config /Users/ovvn/work/myapp/node_modules/@startupjs/e2e/config.js --testNamePattern '^((?!:android:).)*$' --maxWorkers 1 e2e

add `Img` to `ui`

  • It should support a simple src for url
  • and support auto-setting the size of the img when downloaded.

Implement a MobX alternative to the racer model with the same hooks api

Maybe it will completely replace racer alltogether.

Research if we can re-implement racer using MobX-state-tree for the singleton data tree. While keeping the same abstraction layer to work with paths as in racer -- the model abstraction with .at(), .scope(), .get(), .set() methods etc. to easily manipulate the MobX tree.

And research another alternative to MobX - Recoil https://recoiljs.org/

The racer-like API should be optional so that people who are used to work with MobX-state-tree or MobX using the standard approach can still do it.

This will required to do the followin (order might be important, might be not, but discuss with me the proposed architecture of each subtask before starting to implement it):

  • integrate mobx-state-tree with ShareDB for automatic 2-way data synchronisation between them on the client.
  • figure out how to use the same mobx-state-tree together with ShareDB on the server, since our model is supposed to be isomorphic and all the things we can do with model on client should also be possible to do the same way on the server.
  • figure out if it makes sense to implement a racer-like library with the racer-like API on top of all of this -- with the concept of model.at(), model.scope() and other basic methods like model.get(), model.set(), etc.. Implement it if it makes sense.
  • figure out if it makes sense to also re-implement our ORM concept of adding custom methods to scoped models, or if some standard mobx-state-tree way will work better and our own additional abstraction layer on top of it won't make it simpler to use. Implement it if it makes sense.
  • change react-sharedb-hooks observer() and the useDoc, useQuery, etc. hooks implementation to use mobx-react-lite instead of the currently used @nx-js/observer-util

[react-sharedb] - Why react-sharedb is throwing error when we use in some ts(TypeScript) file. Is it not supported?

For any JS or JSX file I have used it is working fine but I am not able to understand such behavior in below scenario :

JS <- react-sharedb -> working fine.
JS <- JS <- react-sharedb -> working fine.
JSX <- JSX/JS <- react-sharedb works fine.
JS <- TS <- react-sharedb -> Not working

Issue is when I create one helper JS file which contains react-sharedb import and then I import that helper file in TS file.
Webpack compiler then tries to compile but later it throws below error:

Error [ERR_REQUIRE_ESM] [ERR_REQUIRE_ESM]: Must use import to load ES Module:

Node Version : 14.16.1
Webpack Version: 5.36.2
React version: 17.0.1
@startupjs/react-sharedb version: 0.29.4

Using URL as Document ID Fails When using .at() and .scope() Methods

We are attempting to create documents with URL based identifiers and are running into some problems with the at() and scope() methods called through the react-sharedb-hooks library for these documents.

Documents appear to be successfully created and are returned when using the useQuery method.

However, when using useDoc for a document with a URL identifier the component fails to load and a warning that the docId is null is output in the console.

When getting the model from a list returned by useQuery using the at function. e.g. $modelList.at(modelDoc.id). and attempting to use this model to perform mutations on the document a "Mutation on uncreated remote document" error is thrown.

Our current theory is that the URL identifier is not getting correctly parsed in the react-sharedb-hooks library.

When digging into the code we came across this line in Doc.js, which might be where this happens for the useDoc hook.

this.subscription = this.model.root.scope(`${collection}.${docId}`)

URL identifiers are necessary for us because we are trying to model JSON-LD documents.

Any help would be appreciated, happy to submit a P.R. if we can identify the appropriate fix.

react-sharedb-hooks standalone usage?

I'd like to use the react-sharedb-hooks package on it's own without startupjs, as I have an application already running with React and sharedb.

When I try to call init, I get a compilation error that /lib/useBackPress.js requires react-native.

Am I doing something wrong here?

Example:

import React, { useEffect, useState } from 'react'
import { Flex } from '@chakra-ui/react'
import ReconnectingWebSocket from 'reconnecting-websocket'

import init from 'startupjs/init'
import racer from 'racer'
import { observer, useDoc } from 'startupjs'

import config from 'config'

racer.Model.prototype._createSocket = function (bundle) {
  console.log(
    '[racer.Model.prototype._createSocket] ReconnectingWebSocket setup'
  )
  const wsProtocol = window.location.protocol.startsWith('https') ? 'wss' : 'ws'
  const socket = new ReconnectingWebSocket(
    `${wsProtocol}://${config('WS_HOST')}`
  )
  return socket
}

init({ baseUrl: config('WS_HOST') })

const RacerDemo = () => {
  const [user, $user] = useDoc('users', 'user-100')
  return (
    <Flex>
      <h1>Racer Demo</h1>
      <h2>User: {user.name}</h2>
    </Flex>
  )
}

export default observer(RacerDemo)

Add Support for URI Model Identifiers (Or any containing .)

We are hoping to use StartupJs to interact with JSON-LD objects, where all our ids will be URIs.

We have opened an issue in racer - derbyjs/racer#289 and are working to add support for this.

However, it is likely that some changes will be required in StartupJs. I think in the orm library. Although thoughts on any other changes required would be welcome.

Opening this to explore whether StartupJs would be open to adopting a P.R for these changes

Create a pug plugin for the TS language server

Implement tags nesting support in CSS

The syntax is gonna be using name of another component as a class name (starting with capital letter):

const MyCard = observer(() => {
  return pug`
    Div.root
      Button= 'Hello World'
  `
  styl`
    .root
      background-color red
    .Button
      background-color green
      &:part(text)
        color blue
  `
})

Implementation:

This is only possible to do for LOCAL css - for styl or css inside the component, like in the example above.

We should make sure the original component name is always there -- debug babel plugin needs to be improved for this to always pass correct original name to observer()

If we see that the component class is used (starting with capital letter) -- we pass its compiled styles object into the wrapping observer() as an option. observer() already sets up Context.Provider so we reuse it to set the styles there.

Down the line in order to get the styles, each component (on observer() level) will use useContext to get the magic function which gets styles from the whole upstream. This function should be passed to all elements which are marked with part.

  • implement parent component functionality - parse LOCAL styles and pass all found component styles to observer as an option
  • implement child component functionality - generate useContext to get a magic function and pass this function to all parts - same as we do with LOCAL - pick a constant name and do typeof __getMagicUpstreamStyles !== 'undefined' && __getMagicUpstreamStyles

Simplify dev environment for startupjs projects

  • by default don't require MongoDB, instead use Mingo sharedb driver and sync data to filesystem. Make sure mingo is the latest version which also supports aggregations and lookups
  • by default don't require Redis, instead use in-memory sharedb pubsub driver

Move react-sharedb and ORM implementation into @startupjs/model monorepo

  • move it out into its own monorepo
  • make sure it can be used standalone in any react project and any express.js project (don't hardcode anything server-specific, it should be easily pluggable to a basic express.js server as a middleware)
  • write docs for it how to use it standalone - make a separate documentation website using the docs startupjs module - the same as our https://startupjs-ui.dev.dmapper.co/. Treat it as a fully standalone project with its own documentation, without any ties to startupjs

[react-sharedb] Fix use* params change race condition

When params change, wait for all use* requests to finish before returning new results for all of them.

On first render save the amount of layers -- track it in the observer() wrapper.

1 layer -- is by default one asynchronous use* hook (useDoc, useQuery, useQueryDoc).

Multiple hooks (not dependent on each other) can explicitly be combined into one layer using useBatch*.

Algorithm:

on initial render:

  1. we start counting the amount of layers.

    Each use* hook increments the counter, except of useBatch* hooks (and maybe useAsync() hooks, need to think about it).

    useBatch() increments counter (this makes it so that all useBatch* hooks before it will be in one layer).

when layer 1 params change:

  1. when executing layer 1 hook we see that its args have changed
  2. set the LOCK flag into observer context that fetching data is in progress -- isFetching
  3. initiate fetching new data for layer 1
  4. set the counter fetchedLayers to 0. This counter will increment when layer 1 finishes getting new data.
  5. synchronously return previous (cached) layer 1 data and proceed to layer 2
  6. for layer 2 we see that isFetching is active and we don't even check layer 2 args
  7. synchronously return previous (cached) layer 2 data
  8. same for layer 3 and further...

when layer 1 gets new data:

  1. save new data for layer 1 somewhere
  2. increment fetchedLayers
  3. sync return OLD cached data for layer 1. We won't return new data for layer 1 until ALL layers fetched the new data
  4. for layer 2 we see that fetchedLayers are now 1 and we need to use NEW data of layer 1 to run layer 2 request.

The API of use* hooks has to be changed to be able to receive a pure function instead of query params -- pure function will receive results of previous hooks:

const [game] = useDoc('games', gameId)
const [players] = useQuery('players', { _id: { $in: game.playerIds } })

// will change to:

const [game] = useDoc('games', gameId)
const [players] = useQuery('players', game => ({ _id: { $in: { game.playerIds } }), [game])

Where game is an ES6 Proxy object which inside the function will be magically referring to the NEW data which was received from the hook

Downside with this api is that you must pass the original game into the function. And you can't just directly pass playerIds, because you have to access the method through Proxy in order to get the new data.

And if someone forgets to pass the root Proxy object from the previous hook then it will just lead to bugs. So if we go with such an API then we'll also have to do some custom eslint rules to catch incorrect usage. As a starting point we might force the function to be pure and only accept top-level Proxy objects from previous hooks as inputs.

Bug with styles

Span.value.small Hello
  .value
    fontFamily('normal', 500)
    font-size 3u
    line-height 4u
    color: $UI.colors.primary
    text-align center

    &.small
      font-size 18px
      line-height 3u

if you write color $UIcolors.primary (wihtout :) then all styles after line-height will be removed for small modifier.

Provide an option to use Next.js on the server-side

  • use Next.js on server-side and web-client
  • and a file-system-based routing option on native because it will probably only work on web
  • find how to mock other next.js-specific things for native (like the ability to set meta tags in , window title, etc.)

[react-sharedb-hooks] Detecting change to query data in useEffect

Is there a recommended way to listen for updates to the underlying data returned by useQuery/useQueryIds? It appears that every time a component using it re-renders, the value returned by the hook is a new reference. As such, detecting changes to the actual data is not possible without using a key/hash of the data returned.

Example (based on the docs Hooks Example)

import React, { useEffect } from 'react'
import {observer, useDoc, useQueryIds, useLocal, useValue} from 'startupjs'

export default observer(function Game ({gameId}) {
  let [secret, setSecret] = useState('Game Secret Password')
  let [game, $game] = useDoc('games', gameId)
  let [players, $players] = useQueryIds('players', game.playerIds)

  // This will fire on each keystroke of changing the input below
  useEffect(() => {
    console.log('players changed')
  }, [players])

  // This will fire when the actual underlying data changes
  useEffect(() => {
    console.log('players actually changed')
  }, [JSON.stringify(players)])

  return (
    <div>
      <label>
        Secret:
        <input type='text' value={secret} onChange={() =>  setSecret(event.target.value)} />
      </label>
    </div>
  )
})

check why `signals: true` doesn't enable the signals and fix it.

Actually lets just make it true by default. It was tested in internal projects pretty intensively so far and seems to be working well. Also lets make observerCache: true by default too.

All of this is in the babel.config.js -- find where the default is set for this flags and change it to true.

This will be a breaking change, so when merging this, don't forget to specify the BREAKING CHANGE: in the merge comment in github (read this)

CSS Variables and color variables refactoring

поскольку стили все как объекты подставляются, то теоретически можно:

  1. эти объекты преобразовывать в обзерваблы, чтобы можно было триггерить ререндеринг при их изменении
  2. вместо подстановки глобальной переменой статически, компилить ее в магическую строку, при этом собирая все используемые переменные в файле стилей конкретного компонента.
  3. мемоизить по этим зависимостям, что уже предусмотрено моей мемоизацией для кэша
  4. в функции processStyleName при смене одной из этих переменных будет заново полноценно исполняться функция получения стилей с реплейсом этой магической строки с названием переменой на значение переменой

import { changeTheme } from 'startupjs'
оно будет синглтоновское
бабель плагин тоже будет на этот синглтон под капотом завязан

и там есть депрекейтед функционал для работы с StyleName, и новый для part
я думаю надо вынести старый депрекейтед в отдельный плагин просто, а новый для part'ов оставить в этом плагине
и потом ворнинги добавить для старого депрекейтед
чтобы StyleName для частей не юзали, а писали именно part всегда и юзали в стилях :part()

Implement css-modules in pure babel, combine web and react-native modes

  • rewrite to pure babel

    The only thing which would need to be added to webpack and metro is adding additional extensions. And that's only if watch is needed in development, otherwise it should be able to compile it on a pure babel config with just the @startupjs/css-modules babel-plugin specified.

  • support both styleName implementation at the same time in one project -- both react-native and pure-web mode

    Decide which one to used based on the imported file extension -- .web.css or .css or .native.css.

    Decide which compilation mode to use for a .css file based on the "cssModulesType" value in package.json -- "web" | "native", default is "native"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.