Skip to content
This repository has been archived by the owner on Nov 17, 2022. It is now read-only.

Commit

Permalink
feat: support route config type (#595)
Browse files Browse the repository at this point in the history
* feat: support route config type

* fix: type

* fix: optimize code
  • Loading branch information
ClarkXia authored Oct 21, 2022
1 parent 7bd90f1 commit 503546a
Show file tree
Hide file tree
Showing 16 changed files with 80 additions and 54 deletions.
5 changes: 3 additions & 2 deletions examples/basic-project/src/pages/about.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Link, useData, useConfig, history } from 'ice';
import type { RouteConfig } from 'ice';
import { isWeb } from '@uni/env';
import url from './ice.png';

Expand All @@ -8,7 +9,7 @@ interface Data {

export default function About() {
const data = useData<Data>();
const config = useConfig();
const config = useConfig<RouteConfig>();

console.log('render About', 'data', data, 'config', config);
console.log('history in component', history);
Expand All @@ -24,7 +25,7 @@ export default function About() {
);
}

export function getConfig() {
export function getConfig(): RouteConfig {
return {
title: 'About',
meta: [
Expand Down
6 changes: 3 additions & 3 deletions examples/basic-project/src/pages/blog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, useData, useConfig } from 'ice';
import { Link, useData, useConfig, defineGetConfig } from 'ice';

export default function Blog() {
const data = useData();
Expand All @@ -14,9 +14,9 @@ export default function Blog() {
);
}

export function getConfig() {
export const getConfig = defineGetConfig(() => {
return {
title: 'Blog',
auth: ['guest'],
};
}
});
6 changes: 4 additions & 2 deletions examples/with-pha/src/pages/home.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { defineGetConfig } from 'ice';

export default function Home() {
return (
<>
Expand All @@ -6,7 +8,7 @@ export default function Home() {
);
}

export function getConfig() {
export const getConfig = defineGetConfig(() => {
return {
queryParamsPassKeys: [
'questionId',
Expand All @@ -15,4 +17,4 @@ export function getConfig() {
],
title: 'Home',
};
}
});
3 changes: 3 additions & 0 deletions packages/ice/src/createService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt
addExportTypes: (exportData: ExportData) => {
generator.addExport('frameworkTypes', exportData);
},
addRouteTypes: (exportData: ExportData) => {
generator.addExport('routeConfigTypes', exportData);
},
addRenderFile: generator.addRenderFile,
addRenderTemplate: generator.addTemplateFiles,
modifyRenderData: generator.modifyRenderData,
Expand Down
14 changes: 9 additions & 5 deletions packages/ice/src/service/runtimeGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
AddExport,
RemoveExport,
AddContent,
GetExportStr,
GetExportData,
ParseRenderData,
Render,
RenderFile,
Expand Down Expand Up @@ -38,6 +38,7 @@ interface Options {
export function generateExports(exportList: ExportData[]) {
const importStatements = [];
let exportStatements = [];
let exportNames: string[] = [];
exportList.forEach(data => {
const { specifier, source, exportAlias, type } = data;
const isDefaultImport = !Array.isArray(specifier);
Expand All @@ -50,6 +51,7 @@ export function generateExports(exportList: ExportData[]) {
} else {
exportStatements.push(`${specifierStr}${symbol}`);
}
exportNames.push(specifierStr);
});
});
return {
Expand All @@ -62,6 +64,7 @@ export function generateExports(exportList: ExportData[]) {
};
*/
exportStr: exportStatements.join('\n '),
exportNames,
};
}

Expand Down Expand Up @@ -118,7 +121,7 @@ export default class Generator {
this.rerender = false;
this.renderTemplates = [];
this.renderDataRegistration = [];
this.contentTypes = ['framework', 'frameworkTypes', 'configTypes'];
this.contentTypes = ['framework', 'frameworkTypes', 'routeConfigTypes'];
// empty .ice before render
fse.emptyDirSync(path.join(rootDir, targetDir));
// add initial templates
Expand Down Expand Up @@ -166,13 +169,14 @@ export default class Generator {
this.contentRegistration[registerKey].push(...content);
};

private getExportStr: GetExportStr = (registerKey, dataKeys) => {
private getExportData: GetExportData = (registerKey, dataKeys) => {
const exportList = this.contentRegistration[registerKey] || [];
const { importStr, exportStr } = generateExports(exportList);
const { importStr, exportStr, exportNames } = generateExports(exportList);
const [importStrKey, exportStrKey] = dataKeys;
return {
[importStrKey]: importStr,
[exportStrKey]: exportStr,
exportNames,
};
};

Expand All @@ -181,7 +185,7 @@ export default class Generator {
const globalStyles = fg.sync([getGlobalStyleGlobPattern()], { cwd: this.rootDir });
let exportsData = {};
this.contentTypes.forEach(item => {
const data = this.getExportStr(item, ['imports', 'exports']);
const data = this.getExportData(item, ['imports', 'exports']);
exportsData = Object.assign({}, exportsData, {
[`${item}`]: data,
});
Expand Down
3 changes: 1 addition & 2 deletions packages/ice/templates/core/env.server.ts.ejs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Define process.env in top make it possible to use ICE_CORE_* in @ice/runtime, esbuild define options doesn't have the ability
// The runtime value such as __process.env.ICE_CORE_*__ will be replaced by esbuild define, so the value is real-time
<% coreEnvKeys.forEach((key) => { %>
process.env.<%= key %> = __process.env.<%= key %>__;
<% }) %>
process.env.<%= key %> = __process.env.<%= key %>__;<% }) %>
12 changes: 8 additions & 4 deletions packages/ice/templates/core/index.ts.ejs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<% if (globalStyle) {-%>
import '<%= globalStyle %>'
<% } -%>

import type { RouteConfig } from './types';
<%- framework.imports %>

<% if (framework.exports) { -%>
type GetConfig = () => RouteConfig;
function defineGetConfig(getConfig: GetConfig): GetConfig {
return getConfig;
}

export {
<%- framework.exports %>
defineGetConfig,
<% if (framework.exports) { -%><%- framework.exports %><% } -%>
};
<% } -%>

export * from './types';
24 changes: 10 additions & 14 deletions packages/ice/templates/core/types.ts.ejs
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import type { AppConfig as DefaultAppConfig, GetAppData, AppData } from '@ice/runtime';
import type { AppConfig, GetAppData, RouteConfig as DefaultRouteConfig } from '@ice/runtime';
<%- routeConfigTypes.imports -%>

<%- configTypes.imports -%>

<% if (configTypes.imports) {-%>
interface ExtendsAppConfig extends DefaultAppConfig {
<% if (configTypes.imports) { %>
<%- configTypes.exports %>
<% } %>
};
export type AppConfig = ExtendsAppConfig;
<% if (routeConfigTypes.imports) {-%>
type ExtendsRouteConfig = <% if (routeConfigTypes.imports) { %><%- routeConfigTypes.exportNames.join(' & ') %><% } %>;
<% } else { -%>
export type AppConfig = DefaultAppConfig;
type ExtendsRouteConfig = {};
<% } -%>
type RouteConfig = DefaultRouteConfig<ExtendsRouteConfig>;

export {
export type {
AppConfig,
GetAppData,
AppData
}
RouteConfig,
};
6 changes: 6 additions & 0 deletions packages/plugin-auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const plugin: Plugin = () => ({
specifier: ['withAuth', 'useAuth'],
source: '@ice/plugin-auth/runtime/Auth',
});

generator.addRouteTypes({
specifier: ['ConfigAuth'],
type: true,
source: '@ice/plugin-auth/esm/types',
});
},
runtime: `${PLUGIN_NAME}/esm/runtime`,
});
Expand Down
4 changes: 4 additions & 0 deletions packages/plugin-auth/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ export type Auth = (data?: any) => Promise<AuthConfig> | AuthConfig;
export function defineAuthConfig(fn: Auth) {
return fn;
}

export interface ConfigAuth {
auth?: string[];
}
7 changes: 6 additions & 1 deletion packages/plugin-pha/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function getDevPath(url: string): string {

const plugin: Plugin<PluginOptions> = (options) => ({
name: '@ice/plugin-pha',
setup: ({ onGetConfig, onHook, context, serverCompileTask }) => {
setup: ({ onGetConfig, onHook, context, serverCompileTask, generator }) => {
const { template } = options || {};
const { command, rootDir } = context;

Expand All @@ -36,6 +36,11 @@ const plugin: Plugin<PluginOptions> = (options) => ({
let getAppConfig: GetAppConfig;
let getRoutesConfig: GetRoutesConfig;

generator.addRouteTypes({
specifier: ['PageConfig'],
type: true,
source: '@ice/plugin-pha/esm/types',
});
// Get server compiler by hooks
onHook(`before.${command as 'start' | 'build'}.run`, async ({ serverCompiler, taskConfigs, urls, ...restAPI }) => {
const taskConfig = taskConfigs.find(({ name }) => name === 'web').config;
Expand Down
7 changes: 3 additions & 4 deletions packages/runtime/src/RouteContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import type { RouteData, RouteConfig } from '@ice/types';
const DataContext = React.createContext<RouteData | undefined>(undefined);
DataContext.displayName = 'Data';

function useData(): RouteData {
function useData<T = any>(): T {
const value = React.useContext(DataContext);
return value;
}
const DataProvider = DataContext.Provider;

const ConfigContext = React.createContext<RouteConfig | undefined>(undefined);
const ConfigContext = React.createContext<RouteConfig<any> | undefined>(undefined);
ConfigContext.displayName = 'Config';

function useConfig(): RouteConfig {
function useConfig<T = {}>(): RouteConfig<T> {
const value = React.useContext(ConfigContext);
return value;
}
Expand All @@ -22,7 +22,6 @@ const ConfigProvider = ConfigContext.Provider;
export {
useData,
DataProvider,

useConfig,
ConfigProvider,
};
2 changes: 1 addition & 1 deletion packages/runtime/src/routesConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const DOMAttributeNames: Record<string, string> = {
noModule: 'noModule',
};

type ElementProps = RouteConfig['meta'] | RouteConfig['links'] | RouteConfig['scripts'];
type ElementProps = RouteConfig['meta'][0] | RouteConfig['links'][0] | RouteConfig['scripts'][0];

/**
* map element props to dom
Expand Down
7 changes: 6 additions & 1 deletion packages/types/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ export type SetPlugins = (plugins: any) => void;
export type AddExport = (registerKey: string, exportData: ExportData | ExportData[]) => void;
export type RemoveExport = (registerKey: string, removeSource: string | string[]) => void;
export type AddContent = (apiName: string, ...args: any) => void;
export type GetExportStr = (registerKey: string, dataKeys: string[]) => { [x: string]: string };
export type GetExportData = (registerKey: string, dataKeys: string[]) => {
imports?: string;
exports?: string;
exportNames?: string[];
[x: string]: any;
};
export type ParseRenderData = () => Record<string, unknown>;
export type Render = () => void;
export type ModifyRenderData = (registration: RenderDataRegistration) => void;
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export interface ExtendsPluginAPI {
generator: {
addExport: AddExport;
addExportTypes: AddExport;
addRouteTypes: AddExport;
addRenderFile: AddRenderFile;
addRenderTemplate: AddTemplateFiles;
modifyRenderData: ModifyRenderData;
Expand Down
27 changes: 12 additions & 15 deletions packages/types/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type { ComponentType, ReactNode, PropsWithChildren } from 'react';
import type { HydrationOptions } from 'react-dom/client';
import type { Navigator, Params } from 'react-router-dom';

type useConfig = () => RouteConfig;
type useData = () => RouteData;
type useAppContext = () => AppContext;
type UseConfig = () => RouteConfig<Record<string, any>>;
type UseData = () => RouteData;
type UseAppContext = () => AppContext;

type VoidFunction = () => void;
type AppLifecycle = 'onShow' | 'onHide' | 'onPageNotFound' | 'onShareAppMessage' | 'onUnhandledRejection' | 'onLaunch' | 'onError' | 'onTabItemClick';
Expand All @@ -20,16 +20,13 @@ export type AppData = any;
export type RouteData = any;

// route.getConfig return value
export interface RouteConfig {
export type RouteConfig<T = {}> = T & {
// Support for extends config.
title?: string;
// TODO: fix type
meta?: any[];
links?: any[];
scripts?: any[];

// plugin extends
auth?: string[];
}
meta?: React.MetaHTMLAttributes<HTMLMetaElement>[];
links?: React.LinkHTMLAttributes<HTMLLinkElement>[];
scripts?: React.ScriptHTMLAttributes<HTMLScriptElement>[];
};

export interface AppExport {
default?: AppConfig;
Expand Down Expand Up @@ -167,9 +164,9 @@ export interface RuntimeAPI {
setRender: SetRender;
addWrapper: AddWrapper;
appContext: AppContext;
useData: useData;
useConfig: useConfig;
useAppContext: useAppContext;
useData: UseData;
useConfig: UseConfig;
useAppContext: UseAppContext;
}

export interface RuntimePlugin {
Expand Down

1 comment on commit 503546a

@vercel
Copy link

@vercel vercel bot commented on 503546a Oct 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

ice-v3 – ./

ice-v3-ice-v3.vercel.app
ice-v3.vercel.app
ice-v3-git-release-next-ice-v3.vercel.app

Please sign in to comment.