-
Notifications
You must be signed in to change notification settings - Fork 8
Feat: define routes and ignore route files #69
Changes from 12 commits
6f3427e
43399de
6129d18
b1d185e
2ed8e69
0847edb
6b14c4f
fe2a872
808b00a
7eae648
bb155b0
e5c4da1
13f5b49
fd71732
a6fce24
a303db2
eff1449
0debd8a
61c2e8b
f451371
5dedac7
6e11fd0
2ea451c
4972237
8ef7f27
1979985
ae4047e
bc1ea1e
a5bc6be
a89cd86
d50e248
09d849d
e3adc08
834d107
f6efb61
3facfd3
636536c
f7ddd64
1c5bd5f
67618a2
cf9fd54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,19 @@ | ||
import { defineUserConfig } from '@ice/app'; | ||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; | ||
// import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; | ||
|
||
export default defineUserConfig({ | ||
publicPath: '/', | ||
webpack: (webpackConfig) => { | ||
if (process.env.NODE_ENV !== 'test') { | ||
webpackConfig.plugins?.push(new BundleAnalyzerPlugin()); | ||
} | ||
return webpackConfig; | ||
// webpack: (webpackConfig) => { | ||
// if (process.env.NODE_ENV !== 'test') { | ||
// webpackConfig.plugins?.push(new BundleAnalyzerPlugin()); | ||
// } | ||
// return webpackConfig; | ||
// }, | ||
routes: { | ||
ignoreFiles: ['about.tsx'], | ||
defineRoutes: (route) => { | ||
route('/about-me', 'about.tsx'); | ||
}, | ||
}, | ||
plugins: ['@ice/plugin-auth'], | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import React from 'react'; | ||
|
||
export default () => { | ||
return ( | ||
<div>data</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import React from 'react'; | ||
|
||
export default () => { | ||
return ( | ||
<div>Dashboard</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import * as React from 'react'; | ||
import { Outlet, Link } from 'ice'; | ||
|
||
export default () => { | ||
return ( | ||
<div> | ||
<h1>Dashboard Layout</h1> | ||
<Link to="/dashboard/data">data</Link> | ||
<Outlet /> | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import React from 'react'; | ||
import { useParams, Link } from 'ice'; | ||
|
||
export default function DetailId() { | ||
const params = useParams(); | ||
|
||
return ( | ||
<div> | ||
<div>Detail Id: {params.id}</div> | ||
<Link to="/detail">Back to Detail</Link> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import React from 'react'; | ||
import { Link } from 'ice'; | ||
|
||
export default function Detail() { | ||
return ( | ||
<div> | ||
<h2>Detail</h2> | ||
<ul> | ||
<li><Link to="/detail/join">join</Link></li> | ||
<li><Link to="/detail/dashboard">dashboard</Link></li> | ||
</ul> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,31 +31,16 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt | |
const templateDir = path.join(__dirname, '../template/'); | ||
const configFile = 'ice.config.(mts|mjs|ts|js|cjs|json)'; | ||
const dataCache = new Map<string, string>(); | ||
|
||
const routesRenderData = generateRoutesInfo(rootDir); | ||
dataCache.set('routes', JSON.stringify(routesRenderData)); | ||
|
||
const generator = new Generator({ | ||
rootDir, | ||
targetDir, | ||
defaultRenderData: { | ||
...routesRenderData, | ||
}, | ||
// add default template of ice | ||
templates: [templateDir], | ||
}); | ||
|
||
const { addWatchEvent, removeWatchEvent } = createWatch({ | ||
watchDir: rootDir, | ||
command, | ||
watchEvents: getWatchEvents({ | ||
generator, | ||
rootDir, | ||
targetDir, | ||
templateDir, | ||
configFile, | ||
cache: dataCache, | ||
}), | ||
}); | ||
|
||
const generatorAPI = { | ||
|
@@ -71,6 +56,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt | |
addRenderFile: generator.addRenderFile, | ||
addRenderTemplate: generator.addTemplateFiles, | ||
}; | ||
|
||
const ctx = new Context<any, ExtendsPluginAPI>({ | ||
rootDir, | ||
command, | ||
|
@@ -89,14 +75,31 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt | |
}, | ||
}); | ||
await ctx.resolveConfig(); | ||
const { userConfig: { routes: routesConfig } } = ctx; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. routes 不存在的情况 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
const routesRenderData = generateRoutesInfo(rootDir, routesConfig); | ||
generator.modifyRenderData((renderData) => ({ | ||
...renderData, | ||
...routesRenderData, | ||
})); | ||
dataCache.set('routes', JSON.stringify(routesRenderData)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里可以顺便优化下仅缓存 manifest 信息 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
generator.setPlugins(ctx.getAllPlugin()); | ||
await ctx.setup(); | ||
|
||
// render template before webpack compile | ||
const renderStart = new Date().getTime(); | ||
|
||
generator.render(); | ||
|
||
addWatchEvent( | ||
...getWatchEvents({ generator, targetDir, templateDir, cache: dataCache, ctx }), | ||
); | ||
|
||
consola.debug('template render cost:', new Date().getTime() - renderStart); | ||
|
||
// define runtime env before get webpack config | ||
defineRuntimeEnv(); | ||
|
||
const contextConfig = getContextConfig(ctx); | ||
const webTask = contextConfig.find(({ name }) => name === 'web'); | ||
const esbuildCompile = createEsbuildCompiler({ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,34 @@ | ||
import * as path from 'path'; | ||
import consola from 'consola'; | ||
import type { WatchEvent } from '@ice/types/esm/plugin.js'; | ||
import type { Context } from 'build-scripts'; | ||
import type { Config } from '@ice/types'; | ||
import { generateRoutesInfo } from './routes.js'; | ||
import type Generator from './service/runtimeGenerator'; | ||
|
||
interface Options { | ||
rootDir: string; | ||
targetDir: string; | ||
templateDir: string; | ||
configFile: string; | ||
generator: Generator; | ||
cache: Map<string, string>; | ||
ctx: Context<Config>; | ||
} | ||
|
||
const getWatchEvents = (options: Options): WatchEvent[] => { | ||
const { rootDir, generator, targetDir, templateDir, configFile, cache } = options; | ||
const { generator, targetDir, templateDir, cache, ctx } = options; | ||
const { userConfig: { routes: routesConfig }, configFile, rootDir } = ctx; | ||
const watchRoutes: WatchEvent = [ | ||
/src\/pages\/?[\w*-:.$]+$/, | ||
(eventName: string) => { | ||
if (eventName === 'add' || eventName === 'unlink') { | ||
const routesRenderData = generateRoutesInfo(rootDir); | ||
const routesRenderData = generateRoutesInfo(rootDir, routesConfig); | ||
const stringifiedData = JSON.stringify(routesRenderData); | ||
if (cache.get('routes') !== stringifiedData) { | ||
cache.set('routes', stringifiedData); | ||
consola.debug('[event]', `routes data regenerated: ${stringifiedData}`); | ||
generator.renderFile( | ||
path.join(templateDir, 'routes.ts.ejs'), | ||
path.join(rootDir, targetDir, 'route.ts'), | ||
path.join(rootDir, targetDir, 'routes.ts'), | ||
routesRenderData, | ||
); | ||
generator.renderFile( | ||
|
@@ -38,6 +40,7 @@ const getWatchEvents = (options: Options): WatchEvent[] => { | |
} | ||
}, | ||
]; | ||
|
||
const watchGlobalStyle: WatchEvent = [ | ||
/src\/global.(scss|less|css)/, | ||
(event: string, filePath: string) => { | ||
|
@@ -49,7 +52,7 @@ const getWatchEvents = (options: Options): WatchEvent[] => { | |
]; | ||
|
||
const watchConfigFile: WatchEvent = [ | ||
new RegExp(configFile), | ||
new RegExp(configFile as string), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 从 ctx 类型上解决 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
(event: string, filePath: string) => { | ||
if (event === 'change') { | ||
consola.warn(`Found a change in ${path.basename(filePath)}. Restart the dev server to see the changes in effect.`); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -104,6 +104,10 @@ const userConfig = [ | |
} | ||
}, | ||
}, | ||
{ | ||
name: 'routes', | ||
validation: 'object', | ||
}, | ||
]; | ||
|
||
const cliOptions = [ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import fse from 'fs-extra'; | ||
import type { RouteItem } from '@ice/runtime'; | ||
|
||
interface Options { | ||
|
@@ -16,7 +16,7 @@ export default async function generateHTML(options: Options) { | |
} = options; | ||
|
||
const serverEntry = await import(entry); | ||
const routes = JSON.parse(fs.readFileSync(routeManifest, 'utf8')); | ||
const routes = JSON.parse(fse.readFileSync(routeManifest, 'utf8')); | ||
const paths = getPaths(routes); | ||
|
||
for (let i = 0, n = paths.length; i < n; i++) { | ||
|
@@ -29,7 +29,9 @@ export default async function generateHTML(options: Options) { | |
}); | ||
|
||
const fileName = routePath === '/' ? 'index.html' : `${routePath}.html`; | ||
fs.writeFileSync(path.join(outDir, fileName), htmlContent); | ||
const contentPath = path.join(outDir, fileName); | ||
await fse.ensureFile(contentPath); | ||
await fse.writeFile(contentPath, htmlContent); | ||
} | ||
} | ||
|
||
|
@@ -38,14 +40,14 @@ export default async function generateHTML(options: Options) { | |
* @param routes | ||
* @returns | ||
*/ | ||
function getPaths(routes: RouteItem[]): string[] { | ||
function getPaths(routes: RouteItem[], parentPath = ''): string[] { | ||
let pathList = []; | ||
|
||
routes.forEach(route => { | ||
if (route.children) { | ||
pathList = pathList.concat(getPaths(route.children)); | ||
pathList = pathList.concat(getPaths(route.children, route.path)); | ||
} else { | ||
pathList.push(route.path || '/'); | ||
pathList.push(path.join('/', parentPath, route.path || '')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SSR 的时候需要特殊处理吗? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 需要的,生成的路由 manifest 中路由第一个字符不是 |
||
} | ||
}); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
import * as path from 'path'; | ||
import { formatNestedRouteManifest, generateRouteManifest } from '@ice/route-manifest'; | ||
import type { NestedRouteManifest } from '@ice/route-manifest'; | ||
import type { UserConfig } from '@ice/types'; | ||
|
||
export function generateRoutesInfo(rootDir: string) { | ||
const routeManifest = generateRouteManifest(rootDir); | ||
export function generateRoutesInfo(rootDir: string, routesConfig?: UserConfig['routes']) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. routesConfig 为 undefined 的情况 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
const routeManifest = generateRouteManifest(rootDir, routesConfig.ignoreFiles, routesConfig.defineRoutes); | ||
const routes = formatNestedRouteManifest(routeManifest); | ||
const str = generateNestRoutesStr(routes); | ||
|
||
|
@@ -23,7 +24,7 @@ function generateNestRoutesStr(nestRouteManifest: NestedRouteManifest[]) { | |
|
||
let str = `{ | ||
path: '${routePath || ''}', | ||
load: () => import(/* webpackChunkName: "${componentName}" */ '@/${componentFile}'), | ||
load: () => import(/* webpackChunkName: "${componentName}" */ '@/pages/${componentFile}'), | ||
componentName: '${componentName}', | ||
index: ${index}, | ||
id: '${id}', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
新建个 example 吧,不要把所有 feature 都放到一个 example 里面
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done