Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support environments api #7045

Open
wants to merge 8 commits into
base: release/4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/multi-dev-server/.browserslistrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
chrome 55
1 change: 1 addition & 0 deletions examples/multi-dev-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build-web2
21 changes: 21 additions & 0 deletions examples/multi-dev-server/ice.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineConfig } from '@ice/app';

export default defineConfig(() => ({
ssr: true,
publicPath: '/web1/',
devPublicPath: '/web1/',
define: {
APP_NAME: JSON.stringify('app-1'),
},
environments: {
web2: {
// fixme: 这里的 publicPath 在 dev 阶段也生效了,这是不符合预期的
publicPath: '/web2/',
outputDir: 'build-web2',
devPublicPath: '/web2/',
define: {
APP_NAME: JSON.stringify('app-2'),
},
},
},
}));
23 changes: 23 additions & 0 deletions examples/multi-dev-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@examples/multi-dev-server",
"private": true,
"version": "1.0.0",
"scripts": {
"start": "ice start",
"build": "ice build"
},
"description": "",
"author": "",
"license": "MIT",
"dependencies": {
"@ice/app": "workspace:*",
"@ice/plugin-rax-compat": "workspace:*",
"@ice/runtime": "workspace:*",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.2"
}
}
Binary file added examples/multi-dev-server/public/favicon.ico
Binary file not shown.
4 changes: 4 additions & 0 deletions examples/multi-dev-server/src/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { defineAppConfig } from 'ice';

// App config, see https://v3.ice.work/docs/guide/basic/app
export default defineAppConfig(() => ({}));
Binary file added examples/multi-dev-server/src/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions examples/multi-dev-server/src/document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* The page's HTML template structure, using JSX.
*/
import { Meta, Title, Links, Main, Scripts } from 'ice';
import { description } from '../package.json';

export default function Document() {
return (
<html>
<head>
<meta charSet="utf-8" />
<meta name="description" content={description} />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
<Meta />
<Title />
<Links />
</head>
<body>
<Main />
<Scripts />
</body>
</html>
);
}
12 changes: 12 additions & 0 deletions examples/multi-dev-server/src/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* The global.css defines the style of the entire project,
* ice.js will globally import this file by default.
*/
:root {
--primary: #3178f6;
--bg-primary: white;
}

body {
margin: 0;
}
15 changes: 15 additions & 0 deletions examples/multi-dev-server/src/pages/about.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default function AboutPage() {
return (
<div>
<h1>About</h1>
<p>This is the about page</p>
<p>
APP_NAME:{' '}
{
// @ts-expect-error
APP_NAME
}
</p>
</div>
);
}
50 changes: 50 additions & 0 deletions examples/multi-dev-server/src/pages/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Style in CSS Modules.
*/

.app {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}

.app > header {
display: flex;
flex-direction: column;
align-items: center;
}

.app > header > img {
width: 120px;
}

.app > header > p {
margin: 20px 0;
text-align: center;
font-size: 2.6rem;
}

.app > main {
display: flex;
flex-direction: column;
margin: 20px 0 10px;
font-size: 0.9rem;
}

.link {
font-size: 1.2rem;
color: var(--primary);
}

.button {
outline: none;
border: none;
border-radius: 8px;
padding: 10px 35px;
background: var(--primary);
box-shadow: 0 5px 10px 0 #ddd;
color: white;
font-size: calc(10px + 2vmin);
}
41 changes: 41 additions & 0 deletions examples/multi-dev-server/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useState } from 'react';
import styles from './index.module.css';
import logo from '@/assets/logo.png';

// @ts-expect-error
console.log(APP_NAME);

export default function IndexPage() {
const [count, setCount] = useState(1);
const updateCount = () => setCount((c) => c + 1);

return (
<div className={styles.app}>
<header>
<img src={logo} alt="logo" />
<p>Hello ice.js 3</p>
<p>
APP_NAME:{' '}
{
// @ts-expect-error
APP_NAME
}
</p>
</header>
<main>
<button className={styles.button} type="button" onClick={updateCount}>
👍🏻 {count}
</button>
<p>
<a href="https://reactjs.org" target="_blank" rel="noopener noreferrer" className={styles.link}>
Learn React
</a>
{' | '}
<a href="https://v3.ice.work/" target="_blank" rel="noopener noreferrer" className={styles.link}>
Learn ice.js
</a>
</p>
</main>
</div>
);
}
1 change: 1 addition & 0 deletions examples/multi-dev-server/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="@ice/app/types" />
32 changes: 32 additions & 0 deletions examples/multi-dev-server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"compileOnSave": false,
"buildOnSave": false,
"compilerOptions": {
"baseUrl": ".",
"outDir": "build",
"module": "esnext",
"target": "ESNext",
"jsx": "react-jsx",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"rootDir": "./",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": false,
"importHelpers": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"skipLibCheck": true,
"paths": {
"@/*": ["./src/*"],
"ice": [".ice"]
}
},
"include": ["src", ".ice", "ice.config.*"],
"exclude": ["build", "public"]
}
64 changes: 47 additions & 17 deletions packages/ice/src/bundler/config/middlewares.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
import type { Compiler } from '@rspack/core';
import type { Compiler, MultiCompiler } from '@rspack/core';
import type { Configuration as DevServerConfiguration } from 'webpack-dev-server';
import type { TaskConfig } from 'build-scripts';
import type { RenderMode } from '@ice/runtime';
import type { Config } from '@ice/shared-config/types';
import type webpack from '@ice/bundles/compiled/webpack/index.js';
import webpackDevMiddleware from '@ice/bundles/compiled/webpack-dev-middleware/index.js';
import createMockMiddleware from '../../middlewares/mock/createMiddleware.js';
import createRenderMiddleware from '../../middlewares/renderMiddleware.js';
import createDataLoaderMiddleware from '../../middlewares/dataLoaderMiddleware.js';
import type { UserConfig } from '../../types/userConfig.js';
import type RouteManifest from '../../utils/routeManifest.js';
import type { GetAppConfig } from '../../types/plugin.js';

export type ICECompiler = Compiler | MultiCompiler | webpack.Compiler | webpack.MultiCompiler;

interface SetupOptions {
userConfig: UserConfig;
taskConfig: TaskConfig<Config>;
routeManifest: RouteManifest;
getAppConfig: GetAppConfig;
excuteServerEntry: () => Promise<any>;
excuteServerEntry: (name?: string) => Promise<any>;
mock: boolean;
rootDir: string;
dataLoaderCompiler?: Compiler;
compiler?: ICECompiler;
allTaskConfigs?: TaskConfig<Config>[];
}

function setupMiddlewares(middlewares: Parameters<DevServerConfiguration['setupMiddlewares']>[0], {
userConfig,
taskConfig,
routeManifest,
getAppConfig,
excuteServerEntry,
mock,
rootDir,
dataLoaderCompiler,
}: SetupOptions) {
function setupMiddlewares(
middlewares: Parameters<DevServerConfiguration['setupMiddlewares']>[0],
{
userConfig,
taskConfig,
routeManifest,
getAppConfig,
excuteServerEntry,
mock,
rootDir,
dataLoaderCompiler,
compiler,
allTaskConfigs,
}: SetupOptions,
) {
const { ssr, ssg } = userConfig;
let renderMode: RenderMode;
// If ssr is set to true, use ssr for preview.
Expand All @@ -49,19 +60,39 @@ function setupMiddlewares(middlewares: Parameters<DevServerConfiguration['setupM
userConfig,
routeManifest,
excuteServerEntry,
allTaskConfigs,
});

// @ts-ignore property of name is exist.
const multiCompilers = (compiler as webpack.MultiCompiler).compilers;
if (Array.isArray(multiCompilers) && multiCompilers.length > 1) {
// @ts-ignore property of name is exist.
middlewares = middlewares.filter(({ name }) => name !== 'webpack-dev-middleware');

multiCompilers.forEach((comp) => {
const devMiddleware = {
name: 'webpack-dev-middleware',
// @ts-ignore property of name is exist.
middleware: webpackDevMiddleware(comp, {
publicPath: comp.options.output.publicPath,
writeToDisk: true,
}),
};

// @ts-ignore property of name is exist.
const insertIndex = middlewares.findIndex(({ name }) => name === 'express-static');
middlewares.splice(insertIndex, 0, devMiddleware);
});
}

if (dataLoaderCompiler) {
const dataLoaderMiddleware = createDataLoaderMiddleware(dataLoaderCompiler);
middlewares.unshift(dataLoaderMiddleware);
}

// @ts-ignore property of name is exist.
const insertIndex = middlewares.findIndex(({ name }) => name === 'serve-index');
middlewares.splice(
insertIndex, 0,
serverRenderMiddleware,
);
middlewares.splice(insertIndex, 0, serverRenderMiddleware);

if (mock) {
const mockMiddleware = createMockMiddleware({ rootDir, exclude: userConfig?.mock?.exclude });
Expand All @@ -70,5 +101,4 @@ function setupMiddlewares(middlewares: Parameters<DevServerConfiguration['setupM
return middlewares;
}


export default setupMiddlewares;
11 changes: 5 additions & 6 deletions packages/ice/src/bundler/config/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function getOutputPaths(options: {
rootDir: string;
outputDir: string;
serverEntry: string;
bundleOptions: Pick<BundlerOptions, 'userConfig' | 'appConfig' | 'routeManifest'>;
bundleOptions: Pick<BundlerOptions, 'userConfig' | 'appConfig' | 'routeManifest'> & { publicPath?: string };
}) {
const { outputDir, serverEntry, bundleOptions, rootDir } = options;
const { userConfig } = bundleOptions;
Expand All @@ -36,14 +36,12 @@ async function buildCustomOutputs(
rootDir: string,
outputDir: string,
serverEntry: string,
bundleOptions: Pick<BundlerOptions, 'userConfig' | 'appConfig' | 'routeManifest'>,
bundleOptions: Pick<BundlerOptions, 'userConfig' | 'appConfig' | 'routeManifest'> & { publicPath?: string },
) {
const { userConfig, appConfig, routeManifest } = bundleOptions;
const { userConfig, appConfig, routeManifest, publicPath } = bundleOptions;
const { ssg } = userConfig;
const routeType = appConfig?.router?.type;
const {
outputPaths = [],
} = await generateEntry({
const { outputPaths = [] } = await generateEntry({
rootDir,
outputDir,
entry: serverEntry,
Expand All @@ -52,6 +50,7 @@ async function buildCustomOutputs(
renderMode: ssg ? 'SSG' : undefined,
routeType: appConfig?.router?.type,
routeManifest,
publicPath,
});
if (routeType === 'memory' && userConfig?.routes?.injectInitialEntry) {
injectInitialEntry(routeManifest, outputDir);
Expand Down
Loading
Loading