mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-01-24 13:45:07 +08:00
feat(renderer): add renderer rootcontext
This commit is contained in:
parent
6f35d1e64f
commit
8b1da55133
@ -31,17 +31,27 @@
|
||||
"@apollo/link-error": "2.0.0-beta.3",
|
||||
"@apollo/link-retry": "2.0.0-beta.3",
|
||||
"@lowdefy/block-tools": "1.0.1-experimental.1",
|
||||
"@lowdefy/engine": "0.0.0-experimental.0",
|
||||
"@lowdefy/get": "1.0.1",
|
||||
"@lowdefy/helpers": "1.0.0",
|
||||
"@lowdefy/layout": "1.0.0",
|
||||
"@lowdefy/set": "1.0.1",
|
||||
"graphql": "15.3.0",
|
||||
"graphql-type-json": "0.3.2",
|
||||
"react": "17.0.0-rc.2",
|
||||
"react-dom": "17.0.0-rc.2"
|
||||
"react-dom": "17.0.0-rc.2",
|
||||
"react-helmet": "6.1.0",
|
||||
"react-router-dom": "5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.11.6",
|
||||
"@babel/preset-react": "7.10.4",
|
||||
"babel-loader": "8.1.0",
|
||||
"bundle-loader": "0.5.6",
|
||||
"css-loader": "4.3.0",
|
||||
"html-webpack-plugin": "4.5.0",
|
||||
"serve": "11.3.2",
|
||||
"style-loader": "2.0.0",
|
||||
"webpack": "5.0.0-rc.4",
|
||||
"webpack-cli": "3.3.12",
|
||||
"webpack-dev-server": "3.11.0"
|
||||
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import { initEmotion } from '@lowdefy/block-tools';
|
||||
import useGqlClient from './utils/useGqlClient';
|
||||
import Page from './Page';
|
||||
|
||||
// const RemoteButton = React.lazy(() => import('block/Button'));
|
||||
|
||||
const Engine = () => {
|
||||
initEmotion();
|
||||
const client = useGqlClient();
|
||||
return (
|
||||
<ApolloProvider client={client}>
|
||||
<h2>App</h2>
|
||||
<Page />
|
||||
</ApolloProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default Engine;
|
@ -20,13 +20,17 @@ import { useQuery } from '@apollo/client';
|
||||
import AutoBlock from './AutoBlock';
|
||||
|
||||
const GET_PAGE = gql`
|
||||
query page {
|
||||
page
|
||||
query page($pageId: ID!) {
|
||||
page(pageId: $pageId)
|
||||
}
|
||||
`;
|
||||
|
||||
const Page = () => {
|
||||
const { loading, error, data } = useQuery(GET_PAGE);
|
||||
const { loading, error, data } = useQuery(GET_PAGE, {
|
||||
variables: {
|
||||
pageId: 'page1',
|
||||
},
|
||||
});
|
||||
if (loading) return <h2>Loading</h2>;
|
||||
if (error) {
|
||||
console.log(error);
|
144
packages/renderer/src/Renderer.js
Normal file
144
packages/renderer/src/Renderer.js
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Route, Redirect, Switch, useLocation } from 'react-router-dom';
|
||||
import { ApolloProvider, useQuery, gql } from '@apollo/client';
|
||||
|
||||
import { ErrorBoundary } from '@lowdefy/block-tools';
|
||||
import get from '@lowdefy/get';
|
||||
|
||||
import useGqlClient from './utils/graphql/useGqlClient';
|
||||
import PageContext from './PageContext';
|
||||
|
||||
import { initEmotion } from '@lowdefy/block-tools';
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const windowContext = window;
|
||||
// eslint-disable-next-line no-undef
|
||||
const documentContext = document;
|
||||
|
||||
const Components = {};
|
||||
const contexts = {};
|
||||
const input = {};
|
||||
|
||||
initEmotion();
|
||||
|
||||
const GET_ROOT = gql`
|
||||
fragment MenuLinkFragment on MenuLink {
|
||||
id
|
||||
type
|
||||
properties
|
||||
pageId
|
||||
url
|
||||
}
|
||||
query getRoot {
|
||||
lowdefyGlobal
|
||||
menu {
|
||||
menus {
|
||||
id
|
||||
menuId
|
||||
properties
|
||||
links {
|
||||
...MenuLinkFragment
|
||||
... on MenuGroup {
|
||||
id
|
||||
type
|
||||
properties
|
||||
links {
|
||||
... on MenuGroup {
|
||||
id
|
||||
type
|
||||
properties
|
||||
links {
|
||||
...MenuLinkFragment
|
||||
}
|
||||
}
|
||||
...MenuLinkFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
homePageId
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const RootContext = ({ children, client }) => {
|
||||
const { data, loading, error } = useQuery(GET_ROOT);
|
||||
if (error) return <h1>Error</h1>;
|
||||
if (loading) return <h1>Loading Root Context</h1>;
|
||||
|
||||
return (
|
||||
<>
|
||||
{children({
|
||||
client,
|
||||
Components,
|
||||
contexts,
|
||||
input,
|
||||
lowdefyGlobal: JSON.parse(JSON.stringify(get(data, 'lowdefyGlobal', { default: {} }))),
|
||||
menus: get(data, 'menu.menus'),
|
||||
homePageId: get(data, 'menu.homePageId'),
|
||||
document: documentContext,
|
||||
window: windowContext,
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Home = ({ rootContext }) => {
|
||||
const { search } = useLocation();
|
||||
if (rootContext.homePageId) {
|
||||
return <Redirect to={{ pathname: `/${rootContext.homePageId}`, search }} />;
|
||||
}
|
||||
return <Redirect to="/404" />;
|
||||
};
|
||||
|
||||
const Root = () => {
|
||||
const client = useGqlClient();
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<ApolloProvider client={client}>
|
||||
<RootContext client={client}>
|
||||
{(rootContext) => {
|
||||
return (
|
||||
<>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Home rootContext={rootContext} />
|
||||
</Route>
|
||||
<Route exact path="/:pageId">
|
||||
<ErrorBoundary>
|
||||
<PageContext rootContext={rootContext} />
|
||||
</ErrorBoundary>
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</RootContext>
|
||||
</ApolloProvider>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
const Engine = () => (
|
||||
<BrowserRouter>
|
||||
<Root />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
export default Engine;
|
7
packages/renderer/src/bootstrap.js
vendored
7
packages/renderer/src/bootstrap.js
vendored
@ -16,5 +16,8 @@
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Engine from './Engine';
|
||||
ReactDOM.render(<Engine />, document.getElementById('root'));
|
||||
|
||||
import './index.css';
|
||||
import Renderer from './Renderer';
|
||||
|
||||
ReactDOM.render(<Renderer />, document.getElementById('root'));
|
||||
|
16
packages/renderer/src/index.css
Normal file
16
packages/renderer/src/index.css
Normal file
@ -0,0 +1,16 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.hide-on-print {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
40
packages/renderer/src/utils/graphql/schema.js
Normal file
40
packages/renderer/src/utils/graphql/schema.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import GraphQLJSON from 'graphql-type-json';
|
||||
|
||||
const typeDefs = gql`
|
||||
extend type Query {
|
||||
block(id: String!): BlockClass
|
||||
pageState(id: String!): PageState
|
||||
}
|
||||
|
||||
type BlockClass {
|
||||
id: String!
|
||||
t: Int
|
||||
}
|
||||
`;
|
||||
|
||||
const GET_BLOCK = gql`
|
||||
fragment getBlockCache on BlockClass @client {
|
||||
id
|
||||
t
|
||||
}
|
||||
`;
|
||||
|
||||
const resolvers = {
|
||||
JSON: GraphQLJSON,
|
||||
Query: {
|
||||
block: (parent, args, { cache }) => {
|
||||
try {
|
||||
return cache.readFragment({
|
||||
id: args.id,
|
||||
fragment: GET_BLOCK,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export { typeDefs, resolvers };
|
@ -20,12 +20,19 @@ import { ApolloClient } from '@apollo/client/core';
|
||||
import { InMemoryCache } from '@apollo/client/cache';
|
||||
import { onError } from '@apollo/link-error';
|
||||
import { RetryLink } from '@apollo/link-retry';
|
||||
import { typeDefs, resolvers } from './schema';
|
||||
|
||||
const cache = new InMemoryCache();
|
||||
const cache = new InMemoryCache({
|
||||
possibleTypes: {
|
||||
MenuItem: ['MenuLink', 'MenuGroup'],
|
||||
},
|
||||
});
|
||||
const retryLink = new RetryLink();
|
||||
const httpLink = new HttpLink({
|
||||
uri: '/graphql',
|
||||
});
|
||||
|
||||
// TODO: Handle errors
|
||||
const errorHandler = ({ graphQLErrors, networkError }) => {
|
||||
console.log('graphQLErrors', graphQLErrors);
|
||||
console.log('networkError', networkError);
|
||||
@ -37,6 +44,8 @@ const useGqlClient = () => {
|
||||
const clt = new ApolloClient({
|
||||
link: ApolloLink.from([retryLink, onError(errorHandler), httpLink]),
|
||||
cache,
|
||||
resolvers,
|
||||
typeDefs,
|
||||
});
|
||||
setClient(clt);
|
||||
}
|
@ -11,6 +11,9 @@ module.exports = {
|
||||
contentBase: path.join(__dirname, 'dist'),
|
||||
port: 3001,
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@ -28,6 +31,17 @@ module.exports = {
|
||||
presets: ['@babel/preset-react'],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader',
|
||||
},
|
||||
{
|
||||
loader: 'css-loader', // translates CSS into CommonJS
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
@ -36,7 +50,7 @@ module.exports = {
|
||||
library: { type: 'var', name: 'lowdefy_renderer' },
|
||||
filename: 'remoteEntry.js',
|
||||
exposes: {
|
||||
'./Engine': './src/Engine',
|
||||
'./Renderer': './src/Renderer',
|
||||
},
|
||||
shared: {
|
||||
...deps,
|
||||
|
Loading…
Reference in New Issue
Block a user