Git Product home page Git Product logo

goji-js's Introduction

GojiJS

Goji Core Goji CLI Create Goji App

React ❤️ Mini Program

中文文档

English Documentation

Visions

GojiJS enables running React code on multi Mini Program platforms.

Features

  • Fully supports React

You can use the latest version of React in GojiJS. Features including class / functional components, hooks, portal can work well on GojiJS.

  • Cross platforms ability

For now, GojiJS supports these platforms:

  • WeChat
  • Baidu
  • Alipay
  • QQ
  • Toutiao

Demo

In GojiJS you can write React code like this:

import React, { useState } from 'react';
import { View, Text, Button, render } from '@goji/core';
import styles from './index.css';

const App = () => {
  const [count, setCount] = useState(0);
  return (
    <View className={styles.wrapped}>
      <Text>{count}</Text>
      <Button onClick={() => setCount(count + 1)}>+</Button>
    </View>
  );
};

render(App);

For more details, see GojiJS official documentation website.

goji-js's People

Contributors

cottom avatar dependabot[bot] avatar jimexist avatar kyeshmz avatar malash avatar remote-star 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  avatar  avatar  avatar

goji-js's Issues

[Proposal] Snapshot and diffing based on copy-on-write DOM tree

What

The DOM tree means the proposal DOM API. For now we can reguard it web's DOM.

const snapshotA = document.createSnapshot();
document.appendChild(document.createElement('view'));
document.appendChild(document.createElement('text'));
document.appendChild(document.createElement('video'));
const snapshotB = document.createSnapshot();

const diffAtoB = generateDiff(snapshotA, snapshotB);
console.log(diffAtoB); // output which DOMs are modified

Why

Immutable snapshot

By using copy-on-write we can create immutable snapshot for eact commit ( setData call ) with low cost. This is useful for diffing algorithm, debug logging and React dev tool supporting. It's imageable that we can even make a DOM history with prev and next buttons to see how the UI changed.

Improve diff generation

In current Goji we generate both data ( full DOM data ) and diff ( part of DOM data for less transfer size ) in the pure method ( however this function is not pure at all 😂 ). There are several known probleams:

  1. The pure methods is expensive becuase it traverse the whole DOM tree every called.
  2. Not same as other VDOM implement, Goji diff generation rely on a tag system that reconciler adds the tag to DOM tree and pure removes the tags. In most cases mutable api is worse then immutable one.
  3. Current implement is too complex to maintain and test. Although write some test cases to cover the corner case we cannot ensure it won't go wrong in production code.

By this proposal we can implement a real pure function the create diff based on two DOM tree:

const diff = generateDiff(oldDom, newDom)

And we can benefit:

  1. Thanks to copy-on-write creating a snapshot is much more cheap and we don't need to mutate the existing DOM tree at all.
  2. We can just use === to check whether a subtree was modified. It is more clear and lite than the tag system.
  3. Immutable API is easier to test.

Support blocking mode

Imaging an use case, we use blocking mode to improve sequency setData calls' performance. If there were 3 commits, useually means business code trigger component re-rendering in different 3 time ticks, the time sequence would be:

6b2d0580-72d3-11ea-9db1-216c91db5bb5

As you can see, besides dataA wo genersate two DOM diff diffAtoB and diffBtoC then merge them as diffAtoC = merge(diffAtoB, diffBtoC). DOM diffing is expensive because it traverses almost the whole DOM tree and figure out which path should be emit.

By using snapshot we can create diff for only once:

// setData A called
lastSnapshot = currentDomTree
// commit B
newSnapshot = currentDomTree
// commot C, override the `newDomTree`
newSnapshot = currentDomTree
// call setData B+C
setData(diff(lastSnapshot, newSnapshot))
// then 
lastSnapshot = newSnapshot
// ...

Memory pool ( optional )

Most copy-on-write system can use reference counting to control the memory usage precisely. After user navgiate to a new page and navigate back so many DOM instances should be GC by V8 virtual matchine. We guess in some platforms the GC won't work as expected and may cause white screen and memory leak issues.

We can maintain a memory pool of DOM elements and reuse the instances as needed. I'm not sure couold it fix the issues but we can exclude some factors of GC probleam.

How

TBD

References

  1. immer
  2. btrfs

Alternative to React and React Reconciler

Since GojiJS is a React-based framework the react and react-reconciler became necessary dependencies that cost about 80kb of the main package size.

-rw-r--r-- 1 malash staff 6.6K Jun 23 12:48 node_modules/react/cjs/react.production.min.js
-rw-r--r-- 1 malash staff 74K Jun 20 16:21 node_modules/react-reconciler/cjs/react-reconciler.production.min.js

As we knew, there are several alternatives to React and React DOM from the opensource community, and some of them, for example, the Preact, can provide the almost same features within as less as 3kb.

This issue proposes to create a new package @goji/react to replace the React and React Reconciler while keeping the API compatibility.

Temporary bugfix for getStorage issue on WeChat SDK 2.24.0

Add these code to your app.js file at the first line.

app.js 的开头添加如下代码:

TypeScript version:

TypeScript 版本:

const patchedGetStorage: typeof wx.getStorage = options => {
  if (!wx.getStorageInfoSync().keys.includes(options.key)) {
    options?.fail?.({ errMsg: 'getStorage:fail data not found' });

    return;
  }
  const data = wx.getStorageSync(options.key);
  options?.success?.({ errMsg: 'getStorage:ok', data });
};

Object.defineProperty(wx, 'getStorage', {
  value: patchedGetStorage,
  writable: false,
  enumerable: true,
  configurable: true,
});

or use JavaScript version:

或者使用 JavaScript 版本:

const patchedGetStorage = options => {
  var _options$success;

  if (!wx.getStorageInfoSync().keys.includes(options.key)) {
    var _options$fail;

    options === null || options === void 0 ? void 0 : (_options$fail = options.fail) === null || _options$fail === void 0 ? void 0 : _options$fail.call(options, {
      errMsg: 'getStorage:fail data not found'
    });
    return;
  }

  const data = wx.getStorageSync(options.key);
  options === null || options === void 0 ? void 0 : (_options$success = options.success) === null || _options$success === void 0 ? void 0 : _options$success.call(options, {
    errMsg: 'getStorage:ok',
    data
  });
};

Object.defineProperty(wx, 'getStorage', {
  value: patchedGetStorage,
  writable: false,
  enumerable: true,
  configurable: true
});

Ref: https://developers.weixin.qq.com/community/develop/doc/000280984dc3781994cdb8c465b800
Ref: https://developers.weixin.qq.com/community/develop/doc/00062e41d4cb082992cdcd7e656400
Ref: https://developers.weixin.qq.com/community/develop/doc/0006ae11bccd902a93cd714ac51000
Ref: https://developers.weixin.qq.com/community/develop/doc/0000624e1f49387a94cde28a151000

[Analysis] Mini Program XML platform differences

The consistency of WXML syntax and features support varies across different platforms, and this project demonstrates those disparities.

Changelog

  • 2022/11/22 Add WeChat/QQ/Baidu/Alipay/Toutiao
  • 2023/10/26 Add Red

Summary

Feature WeChat QQ Baidu Alipay Toutiao Red
Recursive include
Recursive template ⚠️
Recursive components
template variable scope
CSS across include
CSS across template
CSS across component

Features

Recursive include

To test recursive include without cause stack overflow, we can use wx:for with tree-like data.

<!-- a.wxml -->
<block wx:for="{{item.nodes}}">
  <view>item is {{item.name}}</view>
  <include src="./b.wxml" />
</block>
<!-- b.wxml -->
<block wx:for="{{item.nodes}}">
  <view>item is {{item.name}}</view>
  <include src="./a.wxml" />
</block>
  • WeChat ❌

Demo:
https://developers.weixin.qq.com/s/42D0EhmN7ScI

Behavior: Overflowed template call will be ignored and logged.

image

  • QQ ❌

Demo: recursive-include.zip

Behavior: Overflowed template cal will be ignored and rest of loop fails to render.

image

  • Baidu ❌

Demo:
swanide://fragment/97851d9d3dcb480aeec2653a3c5958ac1571642744797

Behavior: Overflowed template call will be ignored and logged.

image

  • Alipay ❌

Demo: recursive-include.zip

Behavior: Whole page rendered failed and logged.

image

  • Toutiao ✅

Demo: https://developer.open-douyin.com/ide/minicode/rQh6Hdn

  • Red ❌

Demo: recursive-include.zip

Behavior: Whole page rendered failed without logging.

Recursive template

To test recursive include without cause stack overflow, we can use wx:for with tree-like data.

<!-- demo.wxml -->
<template name="demo">
  <view>item is {{item.name}}</view>
  <block wx:for="{{item.nodes}}" wx:key="name">
    <template is="demo" data="{{ item: item }}" />
  </block>
</template>
<!-- page.wxml -->
<import src="./demo.wxml" />

<template is="demo" data="{{ ... }}" />
  • WeChat ❌

Demo:
https://developers.weixin.qq.com/s/haGUChm97ZcV

Behavior: Overflowed template call will be ignored and logged.

image

  • QQ ❌

Demo: recursive-template.zip

Behavior: Overflowed template call will be ignored and logged.

image

  • Baidu ⚠️

Demo:
swanide://fragment/cb216847085559c137daaa29bff7dc9d1571645142623

⚠️ Baidu maybe inline all include in complilation instead of runtime and may cause stack
overflow when bundling.

  • Alipay ✅

Demo: recursive-template.zip

  • Toutiao ✅

Demo: https://developer.open-douyin.com/ide/minicode/rQkHTxa

  • Red ✅

Demo: recursive-template.zip

Recursive components

To test recursive include without cause stack overflow, we can use wx:for with tree-like data.

<!-- demo.wxml -->
<view>item is {{item.name}}</view>
<block wx:for="{{item.nodes}}" wx:key="name">
  <demo item="{{item}}" />
</block>
  • WeChat ✅

Demo:
https://developers.weixin.qq.com/s/5Q5EMimk79cZ

  • QQ ✅

Demo: recursive-component.zip

  • Baidu ✅

Demo:
swanide://fragment/04923bc5304ab48fdc8add0e690246171571667693205

  • Alipay ✅

Demo: recursive-components.zip

  • Toutiao ✅

Demo: https://developer.open-douyin.com/ide/minicode/rQkxgET

  • Red ✅

Demo: recursive-components.zip

template variable scope

<!-- page.wxml -->
<block wx:for="{{item.nodes}}" wx:key="name">
  <include src="../wxml/demo" />
</block>
<!-- demo.wxml -->
<view>item is {{item.name}}</view>
  • WeChat ✅

Demo: https://developers.weixin.qq.com/s/ND7WIimE73cL

  • QQ ✅

Demo: template-variable-scope.zip

  • Baidu ✅

Demo:
swanide://fragment/c3991f07e533c0d766013342ac0c97ac1571669430065

  • Alipay ✅

Demo: template-variable-scope.zip

Behavior: template always use page / component variable scope rather than for-loop. It seems Alipay fixed the issue and this feature works now (2023 Q4).

  • Toutiao ✅

Demo: https://developer.open-douyin.com/ide/minicode/rQBBWhC

  • Red ❌

Demo: template-variable-scope.zip

Behavior: template always use page / component variable scope rather than for-loop.

image

CSS across include

Use flex: 1 to test this case. Parent element's styles should effect children's layput.

<!-- flex1.wxml -->
<view class="flex1">flex1</view>
<!-- page.wxml -->
<view class="flex">
  <include src="../wxml/flex1.wxml" />
  <include src="../wxml/flex1.wxml" />
  <include src="../wxml/flex1.wxml" />
</view>

Should render like this:

image

  • WeChat ✅

Demo: https://developers.weixin.qq.com/s/rq79TjmD77cw

  • QQ ✅

Demo: css-across-include.zip

  • Baidu ✅

Demo:
swanide://fragment/7912540f67d19bad1f374b38ff0879421571726087016

  • Alipay ✅

Demo: css-across-include.zip

  • Toutiao ✅

Demo: https://developer.open-douyin.com/ide/minicode/rQB7feV

  • Red ✅

Demo: css-across-include.zip

CSS across template

Similar to previous example but using template.

<!-- page.wxml -->
<template name="flex1">
  <view class="flex1">flex1</view>
</template>

<view class="flex">
  <template is="flex1" />
  <template is="flex1" />
  <template is="flex1" />
</view>
  • WeChat ✅

Demo: https://developers.weixin.qq.com/s/Tc7sFjmf7Kc4

  • QQ ✅

Demo: css-across-template.zip

  • Baidu ❌

Demo:
swanide://fragment/4e23547580fe96fd3730d5d2430548321571726478934

Behavior: demo doesn't work because Baidu Mini Program would create a real element for template
between display: flex and flex: 1.

image

Ref: #226

  • Alipay ✅

Demo: css-across-template.zip

  • Toutiao ✅

Demo: https://developer.open-douyin.com/ide/minicode/idsyNbgf

  • Red ✅

Demo: css-across-template.zip

CSS across component

  • WeChat ❌

Demo:
https://developers.weixin.qq.com/s/ADgm8jmV77c1

Behavior: the flex1 element cause flex layout failed.

image

  • QQ ❌

Demo: css-across-component.zip

Behavior: the flex1 element cause flex layout failed.

image

  • Baidu ❌

Demo:
swanide://fragment/4e20746412ee147bf70436d09c7e4e931571733876570

Behavior: the flex1 element cause flex layout failed.

image

  • Alipay ✅

Demo: css-across-component.zip

image

  • Toutiao ❌

Demo: https://developer.open-douyin.com/ide/minicode/rQSNXsf

Behavior: the flex1 element cause flex layout failed.

image

  • Red ❌

Demo: css-across-component.zip

Behavior: the flex1 element cause flex layout failed.

image

Needed: A Clear Explanation about the Usage of Redux in a Goji.js Project

Is it possible for anyone to elaborate on the usage of Redux in goji.js?

I tried wrapping the Page component with Provider (imported from "react-redux") like you would normally do in a React project, but my app can't load it for some reasons.

The error message in the console reads: "Page[pages/index/index] not found. May be caused by: 1 Forgot to add page route in app.json. 2. Invoking Page() in async task." I suppose it's probably caused by the second one, but I don't know how to fix it.

`<template>` renders to a real DOM element that cause some CSS layout fails on Baidu

Description

This is a well-known issue that Baidu renders as a real DOM element which cause CSS layout fails.

For example,

.flex {
    display: flex;
    flex-direction: row;
}

.flex1 {
    flex: 1;
    border: 2rpx solid black;
}
<template name="item">
    <view class="flex1">hello</view>
</template>

<view class="flex">
    <template is="item"></template>
    <template is="item"></template>
    <template is="item"></template>
</view>

It will renders to

e7d7df80-ce97-11eb-9e89-e37e7d42dd30

The swan-template element may break CSS layout like flex layout.

Reproduct link

swanide://fragment/0f355b2398c107d572e99d92606106381623814792130

Reproduct steps

  1. Open the link
  2. The flex: 1 doesn't work

Impact

Many front-end frameworks like GojiJS / Taro 3 / Remax use a lots of <template> elements as the basic of render engine.

This issue cause more unexpected CSS issues on Baidu than other platforms.

Temporary solution

Developers can write CSS styles for swan-template to solve this issue. But it is not a usual solution.

.flex swan-template {
  flex: 1;
}

Toutiao has a bug of support `rpx` with `!important`

Description

For example height: 200rpx !important; is a line of valid CSS code and it works in Toutiao. But after uglify it becomes height:200rpx!important; and it won't work.

Not all !important statements fail. To reproduce the bug there are several requirements:

  1. Must use rpx. height:200px!important; is ok and also color:red!important is ok.
  2. There shoule be no space before the !important.

Reproduct link

https://developer.toutiao.com/ide/minicode/vpNKxu

Reproduct steps

  1. Open the link
  2. Inspect the elements

95850880-75dc-11ea-89d8-978179aa6d55

Impact

Some CSS failed on Toutiao.

Temporary solution

We can write a Webpack loader to revert the uglify.

module.exports = function main(this: loader.LoaderContext, source: string | Buffer) {
  if (this.cacheable) {
    this.cacheable();
  }

  return source.toString().replace(/!important/g, ' !important');
};

Platforms

  • WeChat
  • Baidu ( including Xiaohongshu )
  • QQ
  • Alipay
  • Toutiao
  • KuaiApp

Missing `e.target.dataset` in event handler when crossing custom component

Description

Consider this DOM tree:

<view bindtap="onClick" data-text="outside">
  <view data-text="inside">Click me</view>
</view>

When clicking on the text Click me, the onClick should be triggered with an event payload that e.target should be the inner element and the e.currentTarget should be the outer element, which means:

  • e.target.dataset.text should be outside
  • e.currentTarget.dataset.text should be inside

But if we move the inner element into a custom component:

<view bindtap="onClick" data-text="outside">
  <comp />
</view>
<!-- comp.wxml -->
<view data-text="inside">Click me</view>

The e.target became unavailable, and the dataset would always be empty.

Reproduct link

Wechat:
https://developers.weixin.qq.com/s/8SSh2Dmk79GI

QQ:
missing-target-id-qq.zip

Reproduct steps

  1. Open demo in WeChat/QQ dev tool.
  2. Click each line.
  3. You could find the e.target.dataset outside custom component is empty.

Impact

GojiJS uses a hacky way to implement stopPropagation:

const id = currentTarget.dataset.gojiId;
const sourceId = target.dataset.gojiId;
const type = camelCase(`on-${(e.type || '').toLowerCase()}`);
const instance = this.instanceMap.get(id);
if (!instance) {
return;
}
let stoppedPropagation = this.stoppedPropagation.get(sourceId);
if (stoppedPropagation && stoppedPropagation.get(type) === timeStamp) {
return;
}
e.stopPropagation = () => {
if (!stoppedPropagation) {
stoppedPropagation = new Map<string, number>();
this.stoppedPropagation.set(sourceId, stoppedPropagation);
}
stoppedPropagation.set(type, timeStamp);
};

It checks the data-goji-id and event timestamp on both target and currentTarget to detect whether the event should be stopped or not. For example, the inner element is clicked and calls stopPropagation, GojiJS would mark this data-goji-id as stopped, then the click handler of outer element trigger and GojiJS find the target.dataset.gojiId was marked and should not run callback anymore.

In this case, the issue described above causes the stopPropagation check to fail.

Temporary solution

We have to refactor the stopPropagation without event dataset dependency. A possible way is that if stopPropagation was called, GojiJS marks clicked element and its ancestors in the virtual dom tree as stoped, the following event on marked elements should be ignored.

Platforms

  • WeChat
  • Baidu ( including Xiaohongshu )
  • QQ
  • Alipay
  • Toutiao
  • KuaiApp

What is the Best Practice for Making a Customized TabBar in Goji.js?

Hi! It's me again! I'm trying to create a TabBar myself instead of using the native WeChat mini-program TabBar which is not customizable and a lot of pain to work with. I'm using the navigator component to build my TabBar, but whenever I click on an navigator, a scroll animation occurs and my TabBar disappears for a second before the next page appears. I have already tried creating a custom-tab-bar folder to store my TabBar as mentioned in WeChat mini-program's official documentation but it just doesn't work in my Goji.js Project. Is there any way I can stop the scroll animation (which typically happens during a page transition) from being applied to my TabBar without making my mini-program a single-page application? Thank you in advance!

Adding gitignore file

Hi!
Thanks for the awesome work in the project.
Just started out using this, but I thought it would be great if we had a gitignore for the starter command line.
There was no contribution document, but I will send a PR if you could have a look!

Thanks

Cannot use React Package react-use-cart

I wired up a simple boilerplate code intergrating both redux and react-use-cart
page/index.js

import React, { useEffect, useState } from "react";
import { render, View, Text, Button } from "@goji/core";
import styles from "./index.css";
import { CartProvider, useCart } from "react-use-cart";
import { Provider } from "react-redux";
import store from "../../store";

const Page = () => {
  const [count, setCount] = useState(0);
  const { setItems } = useCart();
  // useEffect(() => {}, []);
  return (
    <View className={styles.goji}>
      <Text className={styles.goji}>{count}</Text>
      <Button onTap={() => setCount(count + 1)}>Tap ME</Button>
    </View>
  );
};
const CartWrappedApp = () => (
  <CartProvider >
    <Page />
  </CartProvider>
);
const ReduxCartWrappedApp = () => (
  <Provider store={store}>
    <CartWrappedApp />
  </Provider>
);
render(<ReduxCartWrappedApp />);

Unfortunately react-use-cart uses local storage to store its data ,The documentation states that you can pass a storage prop that takes a setter and a getter ,Goji.js doesnt support browser api's such us localstorage I get an error in the dist folder that says

TypeError: Cannot read property 'localStorage' of undefined

I tried using the npm package
https://www.npmjs.com/package/local-storage
I tried polyfilling it failed since you have no place to add a custom webpack configuration stated in the documentation.

Last option the package:
https://github.com/notrab/react-use-cart
takes a props storage which is a function of a getter and setter could you advise me what to use in this position
Regards

[Proposal] New bridge file template engine by React SSR

Why

Bridge files in Goji means the static wxml/wxss/json files generated by Webpack in dist/_goji folder. Now Goji 0.6 use EJS as template engien to generator these files.

But there are some cons of EJS:

  1. No type checking. EJS doesn't support TypeScript.
  2. Hard to abstruct and reuse same templates.
  3. No test case and coverage.

What

I propose to use React and SSR as template engine to generate bridge files.

For example, if you'd like to generate <view wx:if="{{type === 'view'}}"></view> you can use

const BridgeA = () => {
  const type = 'view';
  return <View wxIf={`{{type === '${type}'}}`}></View>
}
console.log(ReactDOMServer.renderToStaticMarkup(<BridgeA />);

How

Here is a full example how to implement this proposal:

import * as React from "react";
import ReactDOMServer from "react-dom/server";

interface CommonBridgeProps {
  className?: string;
  wxIf?: string;
  wxElse?: string;
  wxElif?: string;
  wxFor?: string;
  wxKey?: string;
  wxForItem?: string;
  wxForIndex?: string;
}

function factoryBridgeComponent<Props>(type: string) {
  const comp = (props: React.PropsWithChildren<Props & CommonBridgeProps>) => {
    const {
      wxFor,
      wxIf,
      wxKey,
      wxElse,
      wxElif,
      wxForItem,
      wxForIndex,
      ...restProps
    } = props;
    return React.createElement("" + type, {
      "wx:if": wxIf,
      "wx:else": wxElse,
      "wx:elif": wxElif,
      "wx:for": wxFor,
      "wx:key": wxKey,
      "wx:for-item": wxForItem,
      "wx:for-index": wxForIndex,
      ...restProps
    });
  };
  return comp;
}

const View = factoryBridgeComponent<{ id?: string }>("view");

export default function App() {
  return (
    <View wxFor="xx" wxForItem="bb">
      hi
    </View>
  );
}

const html = ReactDOMServer.renderToStaticMarkup(<App />);
console.log(html);

This proposal solved these probleams:

  1. No type checking. EJS doesn't support TypeScript.
    React and ReactDOM support TypeScript.
  2. Hard to abstruct and reuse same templates.
    We can use React components to regroup bridge templates.
const BridgeA = () => {
  const type = 'view';
  return <View wxIf={`{{type === '${type}'}}`}></View>
}
const BridgeB = () => {
  return <View><BridgeA /><View>;
}
console.log(ReactDOMServer.renderToStaticMarkup(<BridgeB />));
// <view><view wx:if="{{type === 'view'}}"></view></view>
  1. No test case and coverage.
    We can use Jest to write test cases and compute test coverage.

提问:如何复用原生组件?混合开发?和第三方组件?

如何复用原生组件?

这个应用场景主要有以下3点:

  • 内部小程序的特殊组件
    我在某大厂实习,有些内部特殊原生组件gojijs无法适配的,这点可能对gojijs有点苛求了,不过重点在于我没找到对小程序原生组件进行包装的方式,比如说:将 <view /> 包装成 <MyView /> 在 gojijs 中使用的能力
  • 如何在小程序更新后,不需要等待goji-js更新就能用上最新的组件
    同上,当小程序更新了一个新的原生组件后,现有情况下,似乎只能等待 gojijs 对相关组件进行适配更新后才能够在 gojijs 内部使用

混合开发?解决性能敏感页面

一般来讲大部分情况下都不会碰到强求性能的情况,但是总有些情况可能是仅仅在 React 这一层做优化是无法满足的,只能直接上原生页面,这种情况可能很少,但是一旦出现就绕不过去,所以对这点也很好奇gojijs的解决方式

复用第三方组件?

这个同理,大部分第三方组件,特别是 ui 组件,都是通过小程序原生的写法写的,我没有找到很好的办法简单写一下包裹层就直接复用到 gojijs

ps:对这个项目很看好

Recursive `<include>` and `<template>` fails to render if an outside `<include>` existed on Baidu

This is an edge case of using <include> and <temaplte> on Baidu. As I mentioned in #177 , recursive <template> can work on Baidu even with some <include> inside it. Therefore we use children0.swan and components.swan to render GojiJS.

page -------> template--------> include
                ^                  |
                |                  |
                |                  |
                |                  |
                +------------------+

But during refactoring, I found a bug that if you use the same <include> in the page, the rendering stoped at second <include> and no error message was logged.

Here is a reproduction demo: swanide://fragment/407c04e45eba1df09c91e759f4133d8f1669474098159

page -------> include ------> template--------> include (fails to render)
                                ^                  |
                                |                  |
                                |                  |
                                |                  |
                                +------------------+

To solve the issue, you can paste the content of <include> into page's .swan, although it may cost more bundle size.

Some `calc` CSS usages fails on Toutiao

Description

According to official document the whitespace around * and / in a calc function can be ignored. But when using calc with rpx, some cases fail on Toutiao like calc(100rpx*10).

Cases Toutiao Others
calc(20rpx * 10)
calc(20rpx* 10)
calc(20rpx *10)
calc(20rpx*10)

Reproduct link

https://microapp.bytedance.com/ide/minicode/Nvx4ncd

Reproduct steps

Open the link in Toutiao dev tool.

Impact

Because GojiJS uses cssnano to minimize all CSS styles, the whitespaces are removed during Webpack build. It cause some CSS styles fail to run Toutiao.

Temporary solution

  1. Change the options of cssnano to skip this kind of minimization.
  2. Implement a new PostCSS plugin to add whitespaces back.

Platforms

  • WeChat
  • Baidu ( including Xiaohongshu )
  • QQ
  • Alipay
  • Toutiao
  • KuaiApp

Native WeChat Mini-Program Components (Video, Progress, etc.) Unusable

Hi! I just noticed that I can't use several native WeChat mini-program components (such as Video and Progress) in my Goji.js project. It is imperative that I can use at least the Video component in my project. I noticed that many components in the factoryComponents.ts file do not have any props in addition to UnknownProps. Is it an intentional design to accommodate cross-platform performance? If so, is there any workaround for adding Video components to my Goji.js project? (I probably have to rewrite the entire project using Taro if there's no way to use Video components in my project.) Thank you in advance!
Screen Shot 2020-12-11 at 2 54 35 PM

Value changes to`undefined` doesn't work on Baidu template

Description

For data in template <template is="temp" data="{{{ ...obj }}}" />, when value in obj changes from non-undefined to undefined, it doesn't work unless you specify its field like <template is="temp" data="{{{ ...obj, value: obj.value }}}" />.

Reproduct link

swanide://fragment/c44d02fd72c5c1f011dccf3f91ef089e1669272840476

Reproduct steps

Open the link on Baidu dev tool, and click the button on page to see UI changes.

Impact

Some fields may fails to update during page rerendering.

Screen.Recording.2022-11-24.at.14.57.12.mp4

Temporary solution

We have to specify the field manually.

const children = fixBaiduTemplateBug
? t`<template is="$$GOJI_COMPONENT0" data="{{ ...item, sid: item.sid }}" />`
: t`<template is="$$GOJI_COMPONENT0" data="{{ ...item }}" />`;

Platforms

  • WeChat
  • Baidu ( including Xiaohongshu )
  • QQ
  • Alipay
  • Toutiao
  • KuaiApp

'create-goji-app' cannot create an app

PS D:\Projects\TaroifyProjects> yarn create goji-app my-goji-app
yarn create v1.22.11
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...

success Installed "[email protected]" with binaries:
- create-goji-app
[#################################################] 49/49Success! Created my-goji-app at D:\Projects\TaroifyProjects\my-goji-app
Inside that directory, you can run several commands:

yarn start [target]
Start Goji in development mode

yarn build [target]
Start Goji in production mode

The [target] could be one of wechat / baidu / alipay / toutiao / qq / toutiao

We suggest that you begin by typing:

cd my-goji-app
yarn
Done in 5.28s.
PS D:\Projects\TaroifyProjects> cd my-goji-app
cd : 找不到路径“D:\Projects\TaroifyProjects\my-goji-app”,因为该路径不存在。
所在位置 行:1 字符: 1

  • cd my-goji-app
  •   + CategoryInfo          : ObjectNotFound: (D:\Projects\TaroifyProjects\my-goji-app:String) [Set-Location], ItemNotFoundException
      + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand
    
    

PS D:\Projects\TaroifyProjects>

Cannot use <include> in <template> on Alipay

Description

When lib v2 being enabled, <include> in <template> cause compilation error on Alipay dev tool.

image

Reproduct link

lib2-issue.zip

Reproduct steps

  1. Unzip the file
  2. Open in Alipay dev tool 2.7.2

Impact

GojiJS use this feature to import leaf-components in components and fails to run on latest Alipay.

Temporary solution

Replace <include> with src's content.

Platforms

  • WeChat
  • Baidu ( including Xiaohongshu )
  • QQ
  • Alipay
  • Toutiao
  • KuaiApp

What is the Best Practice for Making a Customized TabBar in Goji.js?

Hi @malash! Sorry for the confusion! I don't have much experience submitting issues before. Let me restructure my issue.

Expected Behavior:
Customized TabBar is stuck to the bottom and never disappears.

Current Behavior:
Customized TabBar disappears with the current page whenever there's a page transition. (Scroll Animation)

Possible Solutions:

  1. custom-tab-bar: A custom-tab-bar can be set up in a native WeChat mini-program but it requires the native app to have a "custom-tab-bar" folder at the same level as the pages folder. Even though I tried adding a "custom-tab-bar" folder in the src folder of my Goji.js project, this folder and the files in it just never get compiled.
    source: https://www.jianshu.com/p/91cd8db69739

  2. Making the mini-program a single page application: This will definitely do away with the scroll animation altogether. However, I have to change the structure of my app just to fit a customized TabBar and it might cause future contributors to my app a lot of confusion.
    source: https://github.com/evenyao/wx-diy-tabbar

  3. Some smart Goji/Airbnb way that I don't know yet?

Context (Environment):
Goji.js. Customized TabBar (composed of navigator components) used instead of WeChat mini-program's native TabBar.

Description:
The following is the code that I wrote for my TabBar. It contains multiple Navigators to the main pages, and it is displayed on the main pages.
Screen Shot 2020-11-27 at 9 56 38 AM
Looking forward to your answer!

Originally posted by @Ziyu-Chen in #44 (comment)

Consider to support CSS-in-JS libraries like linaria

Original thread from #31 (comment) @iheyunfei

@malash 有任何办法取消使用 css module 吗? 我在尝试适配一个原生小程序编写的 ui 库到 goji,过程中遇到一些问题。
ui 库也被绑定了 css module 方案
因为现在第三方 ui 库 的 css 文件 一样要走 create-goji-js 中 webpack 的 loader ,ui 库的编写者没法选择是否采用 css module 方案。 虽然总是可以通过使用 :global {} 来达到相同的效果,但这就使得适配过程变得麻烦了许多,如果原来 ui 是用 css 编写还好,只需要每一个文件都加上 :global {} 还比较容易,但是大部分 ui 库为了开发方便都是使用的 less 或 sass 编写,而 less 和 sass 本身与 css module 配合并不是很好,我尝试在 less 内使用 :global {} 语句编译到 css 然后手动适配,但是编译后的 css 代码会报一些很诡异的语法错误。
我个人写项目也是默认使用 css module ,但我觉得把 css module 当作唯一方案可能不利于开发。
建议
这是我想出来的解决方案
或将 css module 的模式定义为可配置项,可以在 goji.config.js 里进行配置相应的 mode。
或将 css module 的模式改为 auto 通过文件命名区分是否启用 css module
适配时将模版改成 jsx 无可厚非,但是如果样式文件没法简单 copy-paste 使用的话,适配就变得比较麻烦了。

[Proposal] Abstruct DOM level API

What

Frameworks like Taro Next and kbone provide the DOM like API to support higher framework. Taro Next call it taro-runtime and kbone exports the API as part of window.document.
In Goji 0.5 the ElementInstance and TextInstance do the same things but somehow coupling with the container.

bf71b000-7215-11ea-89b1-1d00f0acbea2

Why

Multi framework support

By using DOM like API Taro Next support not only React but also VUE. Because there is no need to care about how DOM rendered into view thead in each framework. The DOM API could handle diff logics, event binding, event propagation, blocking mode, setData performance analyzing and etc.

Easier to implement diff generation

For example, we'd like to implement blocking mode, which means block/batch the sequence set data call in a period of time, in the container level. But the most suitable placec is the DOM API. Here is the demo:

document.beginBlockMode();
// change DOM here
document.flushBlockMode();

Code decoupling and easier to test

After more than half-year developing Goji code base became larger and more complex. The current testing progress is render React component => check setData result in TestingAdaptor.

Advanced: Copy-on-write, snapshots and diff

I'll create another issue for this feature.

How

DOM API

Refer to taro-runtime, JSDOM, kbone or MDN DOM and I think it could be acceptable if some APIs are not standard.

We can reuse current ElementInstance and TextInstance ot implement the new DOM API.

Functional design

Some features like pure ( setData generation ) / adaptor calling / blocking mode should be moved into DOM level API. By doing this we can test DOM and TestingAdaptor wihtout React requirement.

And to make code more clear and easy understanding we can publish a new package for this abstruction like @goji/dom.

Support WeChat `plugin://` and Baidu `dynamicLib://`

Background

WeChat plugin and Baidu dynamic lib allow developers reuse existing published third-party components inside their miniapps.

For example, register the component in usingComponents

{
  "usingComponents": {
    "swan-sitemap-list": "dynamicLib://swan-sitemap-lib/swan-sitemap-list"
  }
}

and then you can use <swan-sitemap-list /> in template files.

Use cases

Here are several use cases that I met in our business.

Proposal

I propose a new API call registerPluginComponent.

function registerPluginComponent<T = any>(
  target: 'wechat' | 'baidu',
  componentName: string,
  componentPath: string,
): React.FC<T>
const SwanSitemapList = registerPluginComponent<{ theProp: number }>(
  'baidu',
  'swan-sitemap-list',
  'dynamicLib://swan-sitemap-lib/swan-sitemap-list',
);

render(<SwanSitemapList theProp={1} />);
  1. registerPluginComponent will be static analyzed by Babel or other tools to generate the usingComponents config file.
  2. This API is type-safed, developer could use T to check components props type.
  3. registerPluginComponent should return an empty component on non-registered target. GojiJS should log a warning if developers render an empty component in runtime.

Problems

There are several challenges to support this feature.

Static code analyzing

There are two ways to implement static code analyzing,

  1. Use Babel macros, Remax also use this plan. We have to publish another package like @goji/macro.

  2. Write a custom Babel plugin.

All these plans have a disadvantage the Babel plugin is not pure, that may not work at the same time with Webpack multi thread plugin.

Bundle size

WeChat allow developers to import plugins in specific sub-package rather than the main package. I guess it should reduce the main package bundle size or improve its initial performance ?

But for GojiJS, all bridge files are output into main package's _goji folder. I have to give up this optimization method.

Goji cli not building for alipay

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed

Expected Behavior

When i run npm run build alipay it should create a dist folder with the compiled files.

Current Behavior

What is the current behavior?
When I create a new goji js application when i do cd my-goji-app then npm install it successfully installs dependencies but when i run npm run build alipay i get this error
Screenshot from 2022-11-21 09-48-55
when i install with npm install linaria and run npm run build alipay i get another different error
Screenshot from 2022-11-21 09-57-12
Screenshot from 2022-11-21 09-57-34

Failure Information (for bugs)

This looks like a bug am not sure why this is happening i used windows i also switched to wsl and also installed ubuntu 20 on my machine but the errors are the same i tried changing node versions to older ones but the same errors apperead unfortunately

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

1.npm create goji-app my-goji-app
2.cd my-goji-app
3.npm install
4.npm run build alipay

Context

  • Operating System:Windows 10 & Ubuntu 20 & Wsl

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.