chore: merge master

This commit is contained in:
XXXMrG 2025-03-17 17:15:27 +08:00
commit bead3d70cd
62 changed files with 2676 additions and 1903 deletions

View File

@ -0,0 +1,11 @@
---
'@ice/app': major
'@ice/runtime': minor
'@ice/webpack-config': patch
'@ice/rspack-config': patch
'@ice/shared-config': patch
'@ice/runtime-kit': patch
'@ice/bundles': patch
---
feat: new api and structure for release 4.0

View File

@ -0,0 +1,9 @@
import { defineConfig } from '@ice/app';
import defaultConfig from './ice.config.mjs';
export default defineConfig(() => ({
...defaultConfig,
htmlGenerating: {
mode: 'compat'
}
}));

View File

@ -13,7 +13,12 @@ function Document() {
</head>
<body>
<Main />
<script dangerouslySetInnerHTML={{ __html: 'window.addEventListener(\'suspense\', (d) => console.log(\'suspence event=\', d))' }} />
<script
defer
dangerouslySetInnerHTML={{
__html: "window.addEventListener('ice-suspense', (e) => console.log('ice-suspense', e));",
}}
/>
<Scripts async />
</body>
</html>

View File

@ -11,7 +11,7 @@ export default function Home() {
<h2>Home Page</h2>
<Counter />
<Comments id="comments" fallback={<div>loading...</div>} />
<Footer id="comments" fallback={<div>loading...</div>} />
<Footer id="comments-2" fallback={<div>loading...</div>} />
</div>
);
}

View File

@ -75,8 +75,5 @@
"unplugin@1.6.0": "patches/unplugin@1.6.0.patch",
"@rspack/core@1.2.2": "patches/@rspack__core@1.2.2.patch"
}
},
"workspaces": [
"packages/runtime-kit"
]
}
}

View File

@ -1,5 +1,15 @@
# Changelog
## 0.2.8
### Patch Changes
- 97cb2046: @ice/app: align the output result with the former esbuild
@ice/bundles: export more webpack internal modules
- 97cb2046: @ice/app: remove unused deps and import them from @ice/bundles
@ice/bundles: compile tsconfig-paths-webpack-plugin
- a0099df5: fix: update es-module-lexer
## 0.2.7
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/bundles",
"version": "0.2.7",
"version": "0.2.8",
"license": "MIT",
"author": "ICE",
"description": "Basic dependencies for ice.",
@ -63,7 +63,7 @@
"css-loader": "6.7.1",
"css-minimizer-webpack-plugin": "3.4.1",
"cssnano": "^5.1.7",
"es-module-lexer": "0.10.5",
"es-module-lexer": "1.6.0",
"esbuild-register": "3.4.1",
"eslint": "^8.14.0",
"eslint-webpack-plugin": "3.1.1",

View File

@ -10,6 +10,11 @@ module.exports = {
SingleEntryPlugin: require('webpack/lib/SingleEntryPlugin'),
FetchCompileAsyncWasmPlugin: require('webpack/lib/web/FetchCompileAsyncWasmPlugin'),
FetchCompileWasmPlugin: require('webpack/lib/web/FetchCompileWasmPlugin'),
JavascriptModulesPlugin: require('webpack/lib/javascript/JavascriptModulesPlugin'),
StartupChunkDependenciesPlugin: require('webpack/lib/runtime/StartupChunkDependenciesPlugin'),
StartupHelpers: require('webpack/lib/javascript/StartupHelpers'),
compileBooleanMatcher: require('webpack/lib/util/compileBooleanMatcher'),
identifier: require('webpack/lib/util/identifier'),
StringXor: require('webpack/lib/util/StringXor'),
NormalModule: require('webpack/lib/NormalModule'),
EntryDependency: require('webpack/lib/dependencies/EntryDependency'),

View File

@ -0,0 +1 @@
module.exports = require('./bundle').JavascriptModulesPlugin;

View File

@ -0,0 +1 @@
module.exports = require('./bundle').StartupChunkDependenciesPlugin;

View File

@ -0,0 +1 @@
module.exports = require('./bundle').StartupHelpers;

View File

@ -0,0 +1 @@
module.exports = require('./bundle').compileBooleanMatcher;

View File

@ -0,0 +1 @@
module.exports = require('./bundle').identifier;

View File

@ -1,5 +1,41 @@
# Changelog
## 3.6.0
### Minor Changes
- 97cb2046: support split server bundle
### Patch Changes
- f0c6380b: feat: add htmlGenerating `mode` option
- 97cb2046: @ice/app: align the output result with the former esbuild
@ice/bundles: export more webpack internal modules
- 97cb2046: @ice/app: remove unused deps and import them from @ice/bundles
@ice/bundles: compile tsconfig-paths-webpack-plugin
- 97cb2046: rebase releast/next
- 15cd5f7f: fix: glob pattern for document
- 97cb2046: feat: minify css file;
feat: change minifier from terser to esbuildMinifier.
feat: support config minify option
- 97cb2046: - feat: change transformInclude to array
- fix: only treat .js as jsx
- feat: support customize webpack.module.rule
- feat: support handle assets
- 97cb2046: refactro: reuse webpackConfig
- 97cb2046: fix: use @ice/bundles instead of import webpack directly.
feat: support pass definitions for provide plugin.
- Updated dependencies [97cb2046]
- Updated dependencies [97cb2046]
- Updated dependencies [a0099df5]
- Updated dependencies [a0099df5]
- Updated dependencies [97cb2046]
- @ice/bundles@0.2.8
- @ice/runtime@1.5.2
- @ice/webpack-config@1.2.1
- @ice/shared-config@1.3.1
- @ice/rspack-config@1.2.2
## 3.5.1
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/app",
"version": "3.5.1",
"version": "3.6.0",
"description": "provide scripts and configuration used by web framework ice",
"type": "module",
"main": "./esm/index.js",
@ -54,7 +54,7 @@
"@ice/shared-config": "workspace:*",
"@ice/webpack-config": "workspace:*",
"@ice/rspack-config": "workspace:*",
"@swc/helpers": "0.5.1",
"@swc/helpers": "0.5.15",
"@types/express": "^4.17.14",
"address": "^1.1.2",
"build-scripts": "^2.1.2-0",
@ -62,7 +62,7 @@
"chokidar": "^3.5.3",
"commander": "^9.0.0",
"consola": "^2.15.3",
"cross-spawn": "^7.0.3",
"cross-spawn": "^7.0.5",
"detect-port": "^1.3.0",
"dotenv": "^16.0.0",
"dotenv-expand": "^8.0.3",
@ -70,7 +70,7 @@
"fast-glob": "^3.2.11",
"find-up": "^5.0.0",
"fs-extra": "^10.0.0",
"micromatch": "^4.0.5",
"micromatch": "^4.0.8",
"mlly": "^1.1.0",
"mrmime": "^1.0.0",
"open": "^8.4.0",

View File

@ -5,6 +5,7 @@ import injectInitialEntry from '../../utils/injectInitialEntry.js';
import { SERVER_OUTPUT_DIR } from '../../constant.js';
import { logger } from '../../utils/logger.js';
import type { BundlerOptions } from '../types.js';
import type { HtmlGeneratingMode } from '../../types/index.js';
export async function getOutputPaths(options: {
rootDir: string;
@ -21,7 +22,9 @@ export async function getOutputPaths(options: {
}
}
if (serverEntry && userConfig.htmlGenerating) {
outputPaths = await buildCustomOutputs(rootDir, outputDir, serverEntry, bundleOptions);
const htmlGeneratingMode =
typeof userConfig.htmlGenerating === 'boolean' ? undefined : userConfig.htmlGenerating?.mode;
outputPaths = await buildCustomOutputs(rootDir, outputDir, serverEntry, bundleOptions, htmlGeneratingMode);
}
return outputPaths;
}
@ -37,6 +40,7 @@ async function buildCustomOutputs(
outputDir: string,
serverEntry: string,
bundleOptions: Pick<BundlerOptions, 'userConfig' | 'appConfig' | 'routeManifest'> & { publicPath?: string },
generatingMode?: HtmlGeneratingMode,
) {
const { userConfig, appConfig, routeManifest, publicPath } = bundleOptions;
const { ssg } = userConfig;
@ -51,6 +55,7 @@ async function buildCustomOutputs(
routeType: appConfig?.router?.type,
routeManifest,
publicPath,
generatingMode,
});
if (routeType === 'memory' && userConfig?.routes?.injectInitialEntry) {
injectInitialEntry(routeManifest, outputDir);

View File

@ -508,7 +508,7 @@ const userConfig = [
},
{
name: 'htmlGenerating',
validation: 'boolean',
validation: 'boolean|object',
defaultValue: true,
},
{

View File

@ -28,10 +28,24 @@ export function getHookFiles() {
'webpack/lib/ExternalsPlugin',
'webpack/lib/web/FetchCompileAsyncWasmPlugin',
'webpack/lib/web/FetchCompileWasmPlugin',
'webpack/lib/runtime/StartupChunkDependenciesPlugin',
'webpack/lib/javascript/JavascriptModulesPlugin',
'webpack/lib/javascript/StartupHelpers',
'webpack/lib/util/identifier',
'webpack/lib/util/compileBooleanMatcher',
];
const webpackDir = path.join(require.resolve('@ice/bundles/compiled/webpack'), '../');
const pluginMap = webpackPlugins.map((pluginPath) => {
return [pluginPath, pluginPath.replace(/^webpack\/lib\/((web|node|optimize|webworker)\/)?/, webpackDir)];
return [
pluginPath,
pluginPath.replace(/^webpack\/lib\/((web|node|optimize|webworker|runtime|javascript|util)\/)?/, webpackDir),
];
});
const pluginMapWithJs = webpackPlugins.map((pluginPath) => {
return [
`${pluginPath}.js`,
pluginPath.replace(/^webpack\/lib\/((web|node|optimize|webworker|runtime|javascript|util)\/)?/, webpackDir),
];
});
return [
@ -42,6 +56,7 @@ export function getHookFiles() {
['webpack/hot/only-dev-server', `${webpackDir}hot/only-dev-server`],
['webpack/hot/emitter', `${webpackDir}hot/emitter`],
...pluginMap,
...pluginMapWithJs,
];
}
@ -52,12 +67,7 @@ function hijackWebpack() {
// eslint-disable-next-line global-require
const mod = require('module');
const resolveFilename = mod._resolveFilename;
mod._resolveFilename = function (
request: string,
parent: any,
isMain: boolean,
options: any,
) {
mod._resolveFilename = function (request: string, parent: any, isMain: boolean, options: any) {
const hookResolved = hookPropertyMap.get(request);
if (hookResolved) request = hookResolved;
return resolveFilename.call(mod, request, parent, isMain, options);

View File

@ -27,6 +27,8 @@ import getCSSModuleIdent from '../utils/getCSSModuleIdent.js';
import { scanImports } from './analyze.js';
import type { PreBundleDepsMetaData } from './preBundleDeps.js';
import preBundleDeps from './preBundleDeps.js';
import { WebpackServerCompiler } from './webpackServerCompiler/compiler.js';
import VirualAssetPlugin from './webpackServerCompiler/virtualAssetPlugin.js';
const logger = createLogger('server-compiler');
@ -100,7 +102,6 @@ export function createServerCompiler(options: Options) {
const externals = task.config?.externals || {};
const sourceMap = task.config?.sourceMap;
const dev = command === 'start';
// Filter empty alias.
const { ignores, alias } = filterAlias(task.config?.alias || {});
@ -144,6 +145,7 @@ export function createServerCompiler(options: Options) {
redirectImports,
getRoutesFile,
}, 'esbuild', { isServer });
const define = getRuntimeDefination(task.config?.define || {}, runtimeDefineVars, transformEnv);
if (preBundle) {
const plugins = [
@ -169,7 +171,7 @@ export function createServerCompiler(options: Options) {
plugins,
});
}
server.bundler = server.bundler ?? 'esbuild';
const format = customBuildOptions?.format || 'esm';
let buildOptions: esbuild.BuildOptions = {
@ -236,27 +238,44 @@ export function createServerCompiler(options: Options) {
}
const startTime = new Date().getTime();
logger.debug('[esbuild]', `start compile for: ${JSON.stringify(buildOptions.entryPoints)}`);
logger.debug(`[${server.bundler}]`, `start compile for: ${JSON.stringify(buildOptions.entryPoints)}`);
try {
let esbuildResult: esbuild.BuildResult;
let bundleResult: any;
let context: esbuild.BuildContext;
if (dev) {
context = await esbuild.context(buildOptions);
esbuildResult = await context.rebuild();
bundleResult = await context.rebuild();
} else {
esbuildResult = await esbuild.build(buildOptions);
switch (server.bundler) {
case 'webpack':
const webpackServerCompiler = new WebpackServerCompiler({
...buildOptions,
externals,
compileIncludes: task.config.compileIncludes,
plugins: [compilationInfo && new VirualAssetPlugin({ compilationInfo, rootDir })],
rootDir,
userServerConfig: server,
runtimeDefineVars,
});
bundleResult = (await webpackServerCompiler.build())?.compilation;
break;
case 'esbuild':
default:
bundleResult = await esbuild.build(buildOptions);
break;
}
}
logger.debug('[esbuild]', `time cost: ${new Date().getTime() - startTime}ms`);
logger.debug(`[${server.bundler}]`, `time cost: ${new Date().getTime() - startTime}ms`);
const esm = server?.format === 'esm';
const outJSExtension = esm ? '.mjs' : '.cjs';
const serverEntry = path.join(rootDir, task.config.outputDir, SERVER_OUTPUT_DIR, `index${outJSExtension}`);
if (removeOutputs && esbuildResult.metafile) {
if (removeOutputs && bundleResult.metafile) {
// build/server/a.mjs -> a.mjs
const currentOutputFiles = Object.keys(esbuildResult.metafile.outputs)
const currentOutputFiles = Object.keys(bundleResult.metafile.outputs)
.map(output => output.replace(formatPath(`${path.relative(rootDir, buildOptions.outdir)}${path.sep}`), ''));
const allOutputFiles = fg.sync('**', { cwd: buildOptions.outdir });
const outdatedFiles = difference(allOutputFiles, currentOutputFiles);
@ -264,7 +283,7 @@ export function createServerCompiler(options: Options) {
}
return {
...esbuildResult,
...bundleResult,
context,
serverEntry,
};

View File

@ -0,0 +1,116 @@
import path from 'path';
import { fileURLToPath } from 'url';
import webpack from '@ice/bundles/compiled/webpack/index.js';
import { getWebpackConfig } from '@ice/webpack-config';
import type { UserConfig } from '../../types/userConfig.js';
import { logger } from '../../utils/logger.js';
import { getExpandedEnvs } from '../../utils/runtimeEnv.js';
import { RUNTIME_TMP_DIR } from '../../constant.js';
const _dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
export class WebpackServerCompiler {
private options;
constructor(options: any) {
this.options = options;
}
private async createWebpackConfig(options: {
userServerConfig: UserConfig['server'];
rootDir: string;
[key: string]: any;
}) {
const { userServerConfig } = options;
const { webpackConfig = {} } = userServerConfig;
const definitions = await this.getEsbuildInject();
return getWebpackConfig({
config: {
mode: 'production',
entry: options.entryPoints,
alias: options.alias,
webpackTarget: 'node12.20',
externalsPresets: {
node: false,
},
output: {
filename: `[name].${options.format === 'esm' ? 'mjs' : 'cjs'}`,
path: options.outdir,
// align the output with former esbuild
chunkFormat: false,
clean: true,
library: {
type: 'commonjs2',
},
...(webpackConfig.output as any),
},
plugins: [...options.plugins, ...(webpackConfig.plugins || [])] as any,
externals: options.externals,
outputDir: options.outdir,
enableCache: false,
loaders: [
// Use esbuild to compile JavaScript & TypeScript
{
// // Match `.js`, `.jsx`, `.ts` or `.tsx` files
test: /\.m?[jt]sx?$/,
use: [path.resolve(_dirname, 'removeMagicString.js')],
},
...(webpackConfig.module?.rules || []),
],
useDevServer: false,
analyzer: false,
assetsManifest: false,
define: options.define,
optimization: { ...webpackConfig.optimization } as any,
minify: options.minify,
compileIncludes: webpackConfig.transformInclude,
swcOptions: {
compilationConfig: {
jsc: {
externalHelpers: false,
transform: {
react: {
runtime: options.jsx,
importSource: '@ice/runtime/react',
},
},
},
},
},
definitions,
},
rootDir: options.rootDir,
webpack: webpack as any,
runtimeTmpDir: RUNTIME_TMP_DIR,
userConfigHash: '',
getExpandedEnvs,
isServer: true,
});
}
private async getEsbuildInject(): Promise<Record<string, string | string[]>> {
const provideRecord = {};
const allInjects = await Promise.all(this.options.inject.map((inj) => import(inj)));
allInjects.forEach((injs, index) => {
Object.keys(injs).forEach((key) => {
provideRecord[key] = [this.options.inject[index], key];
});
});
return provideRecord;
}
async build(): Promise<any> {
const config = await this.createWebpackConfig(this.options);
return new Promise((resolve, reject) => {
webpack(config as any, (err, stats) => {
if (err || stats?.hasErrors?.()) {
logger.error(err || stats.toString());
reject(err || stats.toString());
process.exit(1);
} else {
resolve(stats);
}
});
});
}
}

View File

@ -0,0 +1,9 @@
export default function (source: string) {
const result = source.replace(
/webpackChunkName:\s*["'][^"']+["']/g,
'webpackMode: "eager"',
);
// Return the modified source
return result;
}

View File

@ -0,0 +1,42 @@
import { type AssetsManifest } from '@ice/runtime-kit';
import NormalModule from '@ice/bundles/compiled/webpack/NormalModule.js';
import { type Compiler } from '@ice/bundles/compiled/webpack';
interface CompilationInfo {
assetsManifest?: AssetsManifest;
}
const PLUGIN_NAME = 'VirtualManifestPlugin';
class VirtualManifestPlugin {
private rootDir: string;
private compilationInfo: CompilationInfo | (() => CompilationInfo);
constructor(options) {
this.rootDir = options.rootDir;
this.compilationInfo = options.compilationInfo;
}
apply(compiler: Compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory }) => {
NormalModule.getCompilationHooks(compilation)
.readResource.for('virtual')
.tap(PLUGIN_NAME, () => {
const manifest = this.generateManifestContent();
return JSON.stringify(manifest?.assetsManifest || '');
});
normalModuleFactory.hooks.beforeResolve.tap(PLUGIN_NAME, (resolveData) => {
if (resolveData.request === 'virtual:assets-manifest.json') {
resolveData.assertions = {
type: 'json',
};
}
});
});
}
generateManifestContent() {
return typeof this.compilationInfo === 'function' ? this.compilationInfo() : this.compilationInfo;
}
}
export default VirtualManifestPlugin;

View File

@ -2,6 +2,7 @@ import type { DefineRouteFunction, RouteItem } from '@ice/route-manifest';
import type { PluginList } from 'build-scripts';
import type { UnpluginOptions } from '@ice/bundles/compiled/unplugin/index.js';
import type { ProcessOptions } from '@ice/bundles';
import type { Configuration as WebpackConfiguration } from '@ice/bundles/compiled/webpack';
import type { Config, ModifyWebpackConfig, MinimizerOptions } from '@ice/shared-config/types';
import type { OverwritePluginAPI } from './plugin';
import type { EnvironmentUserConfig } from './environment';
@ -50,6 +51,19 @@ interface Fetcher {
method?: string;
}
export type HtmlGeneratingMode = 'cleanUrl' | 'compat';
export interface HtmlGeneratingConfig {
/**
* Control how file structure to generation html.
* Route: '/' '/foo' '/foo/bar'
* `cleanUrl`: '/index.html' '/foo.html' '/foo/bar.html'
* `compat`: '/index.html' '/foo/index.html' '/foo/bar/index.html'
* @default 'cleanUrl'
*/
mode?: HtmlGeneratingMode;
}
export interface UserConfig {
/**
* Feature polyfill for legacy browsers, which can not polyfilled by core-js.
@ -179,7 +193,7 @@ export interface UserConfig {
* HTML will not be generated when build, If it is false.
* @see https://v3.ice.work/docs/guide/basic/config#htmlgenerating
*/
htmlGenerating?: boolean;
htmlGenerating?: boolean | HtmlGeneratingConfig;
/**
* Choose a style of souce mapping to enhance the debugging process.
* @see https://v3.ice.work/docs/guide/basic/config#sourcemap
@ -230,6 +244,22 @@ export interface UserConfig {
* externals config for server bundle
*/
externals?: string[];
/**
* bundler for server bundle, support webpack and esbuild
* @default esbuild
*/
bundler?: 'webpack' | 'esbuild';
/**
* webpack config, only works when bundler is webpack
*/
webpackConfig?: Pick<WebpackConfiguration, 'plugins' | 'optimization' | 'output' | 'module'> & {
/**
* we exclude the node_modules/* by default
*
* use this if you need to transform some packages inside of node_modues
*/
transformInclude?: Array<RegExp | string>;
};
};
/**
* Optimization options for build.

View File

@ -1,6 +1,7 @@
import * as path from 'path';
import fse from 'fs-extra';
import type { ServerContext, RenderMode, AppConfig } from '@ice/runtime';
import type { HtmlGeneratingMode } from '../types/index.js';
import dynamicImport from './dynamicImport.js';
import { logger } from './logger.js';
import type RouteManifest from './routeManifest.js';
@ -12,6 +13,7 @@ interface Options {
documentOnly: boolean;
routeType: AppConfig['router']['type'];
renderMode?: RenderMode;
generatingMode?: HtmlGeneratingMode;
routeManifest: RouteManifest;
publicPath?: string;
}
@ -21,7 +23,8 @@ interface EntryResult {
}
export default async function generateEntry(options: Options): Promise<EntryResult> {
const { rootDir, entry, outputDir, documentOnly, renderMode, routeType, routeManifest, publicPath } = options;
const { rootDir, entry, outputDir, documentOnly, renderMode, routeType, routeManifest, publicPath, generatingMode } =
options;
let serverEntry: string;
try {
@ -39,7 +42,7 @@ export default async function generateEntry(options: Options): Promise<EntryResu
const { htmlOutput } = await renderEntry({ routePath, serverEntry, documentOnly, renderMode, publicPath });
const generateOptions = { rootDir, routePath, outputDir };
if (htmlOutput) {
const path = await generateFilePath({ ...generateOptions, type: 'html' });
const path = await generateFilePath({ ...generateOptions, type: 'html', generatingMode });
await writeFile(path, htmlOutput);
outputPaths.push(path);
}
@ -60,8 +63,18 @@ export function escapeRoutePath(str: string) {
return str.replace(/\/(:|\*)/g, '/$');
}
function formatFilePath(routePath: string, type: 'js' | 'html' | 'js.map'): string {
return routePath === '/' ? `index.${type}` : `${escapeRoutePath(routePath)}.${type}`;
function formatFilePath(
routePath: string,
type: 'js' | 'html' | 'js.map',
generatingMode?: HtmlGeneratingMode,
): string {
if (routePath === '/') {
return `index.${type}`;
}
if (type === 'html' && generatingMode === 'compat') {
return `${escapeRoutePath(routePath)}/index.${type}`;
}
return `${escapeRoutePath(routePath)}.${type}`;
}
async function generateFilePath({
@ -69,13 +82,15 @@ async function generateFilePath({
routePath,
outputDir,
type,
generatingMode,
}: {
rootDir: string;
routePath: string;
outputDir: string;
type: 'js' | 'html' | 'js.map';
generatingMode?: HtmlGeneratingMode;
}) {
const fileName = formatFilePath(routePath, type);
const fileName = formatFilePath(routePath, type, generatingMode);
if (fse.existsSync(path.join(rootDir, 'public', fileName))) {
logger.warn(`${fileName} is overwrite by framework, rename file name if it is necessary.`);
}

View File

@ -2,7 +2,7 @@ import * as path from 'path';
import fg from 'fast-glob';
export default function hasDocument(rootDir: string) {
const document = fg.sync('document.{tsx,ts,jsx.js}', {
const document = fg.sync('document.{tsx,ts,jsx,js}', {
cwd: path.join(rootDir, 'src'),
});
return document.length > 0;

View File

@ -35,7 +35,7 @@
],
"dependencies": {
"style-unit": "^3.0.4",
"@swc/helpers": "^0.5.13"
"@swc/helpers": "^0.5.15"
},
"devDependencies": {
"@ice/pkg": "^1.5.0",

View File

@ -1,5 +1,14 @@
# @ice/miniapp-loader
## 1.2.1
### Patch Changes
- Updated dependencies [97cb2046]
- Updated dependencies [97cb2046]
- Updated dependencies [a0099df5]
- @ice/bundles@0.2.8
## 1.2.0
### Minor Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/miniapp-loader",
"version": "1.2.0",
"version": "1.2.1",
"description": "webpack loader for miniapps.",
"main": "./lib/page.js",
"files": [

View File

@ -1,5 +1,11 @@
# @ice/miniapp-react-dom
## 1.1.2
### Patch Changes
- @ice/miniapp-runtime@1.2.2
## 1.1.1
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/miniapp-react-dom",
"version": "1.1.1",
"version": "1.1.2",
"description": "like react-dom, but for miniapps.",
"type": "module",
"types": "./esm/index.d.ts",

View File

@ -1,5 +1,12 @@
# Changelog
## 1.2.2
### Patch Changes
- Updated dependencies [a0099df5]
- @ice/runtime@1.5.2
## 1.2.1
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/miniapp-runtime",
"version": "1.2.1",
"version": "1.2.2",
"description": "ice runtime for miniapps.",
"type": "module",
"types": "./esm/index.d.ts",

View File

@ -40,7 +40,7 @@
],
"dependencies": {
"@ice/jsx-runtime": "^0.3.1",
"@swc/helpers": "^0.5.1",
"@swc/helpers": "^0.5.15",
"accept-language-parser": "^1.5.0",
"universal-cookie": "^4.0.4",
"url-join": "^5.0.0"
@ -56,8 +56,8 @@
"webpack-dev-server": "5.0.4"
},
"peerDependencies": {
"@ice/app": "^3.5.1",
"@ice/runtime": "^1.5.1"
"@ice/app": "^3.6.0",
"@ice/runtime": "^1.5.2"
},
"publishConfig": {
"access": "public"

View File

@ -1,5 +1,17 @@
# Changelog
## 1.2.2
### Patch Changes
- Updated dependencies [97cb2046]
- Updated dependencies [97cb2046]
- Updated dependencies [a0099df5]
- @ice/bundles@0.2.8
- @ice/miniapp-loader@1.2.1
- @ice/miniapp-runtime@1.2.2
- @ice/miniapp-react-dom@1.1.2
## 1.2.1
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/plugin-miniapp",
"version": "1.2.1",
"version": "1.2.2",
"description": "ice.js plugin for miniapp.",
"license": "MIT",
"type": "module",
@ -50,8 +50,8 @@
"sax": "^1.2.4"
},
"devDependencies": {
"@ice/app": "^3.5.1",
"@ice/runtime": "^1.5.1",
"@ice/app": "^3.6.0",
"@ice/runtime": "^1.5.2",
"webpack": "^5.88.0"
},
"repository": {

View File

@ -1,5 +1,12 @@
# Changelog
## 0.4.0
### Minor Changes
- Updated dependencies [bbeeaf5d]
- rax-compat@0.4.0
## 0.3.2
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/plugin-rax-compat",
"version": "0.3.2",
"version": "0.4.0",
"description": "Provide rax compat support for ice.js",
"license": "MIT",
"type": "module",
@ -25,7 +25,7 @@
"consola": "^2.15.3",
"css": "^2.2.1",
"lodash-es": "^4.17.21",
"rax-compat": "^0.3.0",
"rax-compat": "^0.4.0",
"style-unit": "^3.0.5",
"stylesheet-loader": "^0.9.1"
},

View File

@ -8,7 +8,7 @@ interface RequestResult<R, P extends any[]> extends Result<R, P> {
requestAsync: Result<R, P>['runAsync'];
}
export function useRequest<TData, TParams extends any[] = []>(
export function useRequest<TData, TParams extends any[]>(
service: string | AxiosRequestConfig | Service<TData, TParams>,
options?: Options<TData, TParams>,
plugins?: Plugin<TData, TParams>[]) {

View File

@ -41,7 +41,7 @@
"dependencies": {
"@ice/store": "^2.0.3",
"fast-glob": "^3.2.11",
"micromatch": "^4.0.5"
"micromatch": "^4.0.8"
},
"devDependencies": {
"@ice/app": "workspace:^",

View File

@ -1,5 +1,11 @@
# Changelog
## 0.4.0
### Minor Changes
- bbeeaf5d: fix: fix svg
## 0.3.0
### Minor Changes

View File

@ -1,6 +1,6 @@
{
"name": "rax-compat",
"version": "0.3.0",
"version": "0.4.0",
"description": "Rax compatible mode, running rax project on the react runtime.",
"files": [
"esm",
@ -100,7 +100,7 @@
],
"dependencies": {
"@ice/appear": "^0.2.1",
"@swc/helpers": "^0.5.1",
"@swc/helpers": "^0.5.15",
"style-unit": "^3.0.5"
},
"devDependencies": {

View File

@ -17,7 +17,7 @@ export function createJSXElementFactory(factory: typeof ElementFactory) {
// Compat for props.
if (isRealDOM) {
// Only the dom needs to be transformed, not the components.
rest = transformProps(rest);
rest = transformProps(type, rest);
// Delete props on real dom that are not allowed in react.
delete rest.onAppear;

View File

@ -24,6 +24,161 @@ const possibleStandardNames = [
// meta
'charSet',
'dangerouslySetInnerHTML',
'strokeWidth',
// SVG
'accentHeight',
'accumulate',
'additive',
'alignmentBaseline',
'allowReorder',
'arabicForm',
'attributeName',
'attributeType',
'autoReverse',
'baseFrequency',
'baselineShift',
'baseProfile',
'calcMode',
'capHeight',
'clipPath',
'clipPathUnits',
'clipRule',
'colorInterpolation',
'colorInterpolationFilters',
'colorProfile',
'colorRendering',
'contentScriptType',
'contentStyleType',
'diffuseConstant',
'dominantBaseline',
'edgeMode',
'enableBackground',
'externalResourcesRequired',
'fillOpacity',
'fillRule',
'filterRes',
'filterUnits',
'floodOpacity',
'floodColor',
'fontFamily',
'fontSize',
'fontSizeAdjust',
'fontStretch',
'fontStyle',
'fontVariant',
'fontWeight',
'glyphName',
'glyphOrientationHorizontal',
'glyphOrientationVertical',
'glyphRef',
'gradientTransform',
'gradientUnits',
'hanging',
'horizAdvX',
'horizOriginX',
'ideographic',
'imageRendering',
'kernelMatrix',
'kernelUnitLength',
'keyPoints',
'keySplines',
'keyTimes',
'lengthAdjust',
'letterSpacing',
'lightingColor',
'limitingConeAngle',
'markerEnd',
'markerHeight',
'markerMid',
'markerStart',
'markerUnits',
'markerWidth',
'maskContentUnits',
'maskUnits',
'numOctaves',
'overlinePosition',
'overlineThickness',
'paintOrder',
'pathLength',
'patternContentUnits',
'patternTransform',
'patternUnits',
'pointerEvents',
'pointsAtX',
'pointsAtY',
'pointsAtZ',
'preserveAlpha',
'preserveAspectRatio',
'primitiveUnits',
'refX',
'refY',
'renderingIntent',
'repeatCount',
'repeatDur',
'requiredExtensions',
'requiredFeatures',
'shapeRendering',
'specularConstant',
'specularExponent',
'spreadMethod',
'startOffset',
'stdDeviation',
'stitchTiles',
'stopColor',
'stopOpacity',
'strikethroughPosition',
'strikethroughThickness',
'strokeDasharray',
'strokeDashoffset',
'strokeLinecap',
'strokeLinejoin',
'strokeMiterlimit',
'strokeWidth',
'strokeOpacity',
'suppressContentEditableWarning',
'suppressHydrationWarning',
'surfaceScale',
'systemLanguage',
'tableValues',
'targetX',
'targetY',
'textAnchor',
'textDecoration',
'textLength',
'textRendering',
'underlinePosition',
'underlineThickness',
'unicodeBidi',
'unicodeRange',
'unitsPerEm',
'vAlphabetic',
'vectorEffect',
'vertAdvY',
'vertOriginX',
'vertOriginY',
'vHanging',
'vIdeographic',
'viewBox',
'viewTarget',
'visibility',
'vMathematical',
'wordSpacing',
'writingMode',
'xChannelSelector',
'xHeight',
'xlinkActuate',
'xlinkArcrole',
'xlinkHref',
'xlinkRole',
'xlinkShow',
'xlinkTitle',
'xlinkType',
'xmlBase',
'xmlLang',
'xmlnsXlink',
'xmlSpace',
'yChannelSelector',
'zoomAndPan',
].reduce((records: Record<string, string>, iter: string) => {
records[iter.toLowerCase()] = iter;
return records;

View File

@ -8,7 +8,7 @@ function isEventLikeProp(key: string) {
return key.indexOf('on') === 0;
}
function transformProps(props: ComponentProps<JSXElementConstructor<any>>): Record<string, any> {
function transformProps(type: string, props: ComponentProps<JSXElementConstructor<any>>): Record<string, any> {
const transformedProps: Record<string, any> = {};
Object.keys(props).forEach((propKey: string) => {
let key: string = propKey;
@ -21,19 +21,21 @@ function transformProps(props: ComponentProps<JSXElementConstructor<any>>): Reco
// etc...
if (isEventLikeProp(lowerCasedPropKey)) {
if (registrationNameToReactEvent.has(lowerCasedPropKey)) {
const reactEvent: string = registrationNameToReactEvent.get(lowerCasedPropKey);
const reactEvent: string = registrationNameToReactEvent.get(lowerCasedPropKey) || '';
if (reactEvent !== propKey) {
key = reactEvent;
}
}
// eslint-disable-next-line no-prototype-builtins
} else if (possibleStandardNames.hasOwnProperty(lowerCasedPropKey)) {
} else {
if (Object.prototype.hasOwnProperty.call(possibleStandardNames, lowerCasedPropKey)) {
// Transform attribute names that make it works properly in React.
key = possibleStandardNames[lowerCasedPropKey];
} else {
// Handles component props from rax-components like resizeMode, this causes React to throw a warning.
key = lowerCasedPropKey;
}
}
transformedProps[key] = val;
});

View File

@ -37,82 +37,85 @@ describe('events', () => {
});
it('should work with ontouchstart', () => {
expect(transformProps({
expect(transformProps('div', {
ontouchstart: () => { },
}).onTouchStart).toBeInstanceOf(Function);
});
it('should work with onclick', () => {
expect(transformProps({
expect(transformProps('div', {
onclick: () => { },
}).onClick).toBeInstanceOf(Function);
expect(transformProps({
expect(transformProps('div', {
onclick: () => { },
}).onclick).toBe(undefined);
});
it('should work with onClick', () => {
expect(transformProps({
expect(transformProps('div', {
onClick: () => { },
}).onClick).toBeInstanceOf(Function);
});
it('should work with ondblclick', () => {
expect(transformProps({
console.log('aaaaaa', transformProps('div', {
ondblclick: () => { },
}));
expect(transformProps('div', {
ondblclick: () => { },
}).onDoubleClick).toBeInstanceOf(Function);
expect(transformProps({
expect(transformProps('div', {
ondblclick: () => { },
}).ondblclick).toBe(undefined);
});
it('should work with onDblclick', () => {
expect(transformProps({
expect(transformProps('div', {
onDblclick: () => { },
}).onDoubleClick).toBeInstanceOf(Function);
expect(transformProps({
expect(transformProps('div', {
onDblclick: () => { },
}).onDblclick).toBe(undefined);
});
it('should work with onDoubleClick', () => {
expect(transformProps({
expect(transformProps('div', {
onDoubleClick: () => { },
}).onDoubleClick).toBeInstanceOf(Function);
});
it('should work with onmouseenter', () => {
expect(transformProps({
expect(transformProps('div', {
onmouseenter: () => { },
}).onMouseEnter).toBeInstanceOf(Function);
expect(transformProps({
expect(transformProps('div', {
onmouseenter: () => { },
}).onmouseenter).toBe(undefined);
});
it('should work with onpointerenter', () => {
expect(transformProps({
expect(transformProps('div', {
onpointerenter: () => { },
}).onPointerEnter).toBeInstanceOf(Function);
expect(transformProps({
expect(transformProps('div', {
onpointerenter: () => { },
}).onpointerenter).toBe(undefined);
});
it('should work with onchange', () => {
expect(transformProps({
expect(transformProps('div', {
onchange: () => { },
}).onChange).toBeInstanceOf(Function);
expect(transformProps({
expect(transformProps('div', {
onchange: () => { },
}).onchange).toBe(undefined);
});
it('should work with onbeforeinput', () => {
expect(transformProps({
expect(transformProps('div', {
onbeforeinput: () => { },
}).onBeforeInput).toBeInstanceOf(Function);
expect(transformProps({
expect(transformProps('div', {
onbeforeinput: () => { },
}).onbeforeinput).toBe(undefined);
});

View File

@ -7,44 +7,44 @@ import transformProps from '../src/props';
describe('props', () => {
it('should work with autofocus', () => {
expect(transformProps({
expect(transformProps('div', {
autofocus: true,
}).autoFocus).toBe(true);
});
it('should work with autoplay', () => {
expect(transformProps({
expect(transformProps('div', {
autoplay: true,
}).autoPlay).toBe(true);
});
it('should work with classname', () => {
expect(transformProps({
expect(transformProps('div', {
classname: 'class',
}).className).toBe('class');
});
it('should work with crossorigin', () => {
expect(transformProps({
expect(transformProps('div', {
crossorigin: 'xxx',
}).crossOrigin).toBe('xxx');
});
it('should work with maxlength', () => {
expect(transformProps({
expect(transformProps('div', {
maxlength: '10',
}).maxLength).toBe('10');
});
it('should work with inputmode', () => {
expect(transformProps({
expect(transformProps('div', {
inputmode: 'numeric',
}).inputMode).toBe('numeric');
});
it('should work with dangerouslySetInnerHTML', () => {
expect(
transformProps({
transformProps('div', {
dangerouslySetInnerHTML: { __html: 'xxx' },
}).dangerouslySetInnerHTML,
).toEqual({

View File

@ -1,5 +1,16 @@
# @ice/rspack-config
## 1.2.2
### Patch Changes
- Updated dependencies [97cb2046]
- Updated dependencies [97cb2046]
- Updated dependencies [a0099df5]
- Updated dependencies [97cb2046]
- @ice/bundles@0.2.8
- @ice/shared-config@1.3.1
## 1.2.1
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/rspack-config",
"version": "1.2.1",
"version": "1.2.2",
"repository": "alibaba/ice",
"bugs": "https://github.com/alibaba/ice/issues",
"homepage": "https://v3.ice.work",
@ -15,8 +15,8 @@
"*.d.ts"
],
"dependencies": {
"@ice/bundles": "0.2.7",
"@ice/shared-config": "1.3.0"
"@ice/bundles": "0.2.8",
"@ice/shared-config": "1.3.1"
},
"devDependencies": {
"@rspack/core": "1.2.2"

View File

@ -1,5 +1,11 @@
# @ice/runtime
## 1.5.2
### Patch Changes
- a0099df5: feat: post event for each suspense.
## 1.5.1
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/runtime",
"version": "1.5.1",
"version": "1.5.2",
"description": "Runtime module for ice.js",
"type": "module",
"types": "./esm/index.d.ts",

View File

@ -156,6 +156,11 @@ export function withSuspense(Component) {
<SuspenseContext.Provider value={suspenseState}>
<Component {...componentProps} />
<Data id={id} />
<script
dangerouslySetInnerHTML={{
__html: `window.dispatchEvent(new CustomEvent('ice-suspense', { detail: { id: ${id ? `'${id}'` : undefined} } }));`,
}}
/>
</SuspenseContext.Provider>
</React.Suspense>
);
@ -166,6 +171,11 @@ function Data(props) {
const data = useSuspenseData();
return (
<script dangerouslySetInnerHTML={{ __html: `!function(){window['${LOADER}'] = window['${LOADER}'] || {};window['${LOADER}']['${props.id}'] = ${JSON.stringify(data)}}();` }} />
<script
id={props.id && `suspense-script-${props.id}`}
dangerouslySetInnerHTML={{
__html: `!function(){window['${LOADER}'] = window['${LOADER}'] || {};window['${LOADER}']['${props.id}'] = ${JSON.stringify(data)}}();`,
}}
/>
);
}

View File

@ -1,5 +1,16 @@
# @ice/shared-config
## 1.3.1
### Patch Changes
- 97cb2046: fix: use @ice/bundles instead of import webpack directly.
feat: support pass definitions for provide plugin.
- Updated dependencies [97cb2046]
- Updated dependencies [97cb2046]
- Updated dependencies [a0099df5]
- @ice/bundles@0.2.8
## 1.3.0
### Minor Changes

View File

@ -1,6 +1,6 @@
{
"name": "@ice/shared-config",
"version": "1.3.0",
"version": "1.3.1",
"repository": "alibaba/ice",
"bugs": "https://github.com/alibaba/ice/issues",
"homepage": "https://v3.ice.work",
@ -17,7 +17,7 @@
"*.d.ts"
],
"dependencies": {
"@ice/bundles": "0.2.7",
"@ice/bundles": "0.2.8",
"@rollup/pluginutils": "^4.2.0",
"browserslist": "^4.22.1",
"consola": "^2.15.3",

View File

@ -1,11 +1,6 @@
import type webpack from '@ice/bundles/compiled/webpack';
import type { RuleSetRule, Configuration, Compiler, WebpackPluginInstance } from '@ice/bundles/compiled/webpack';
import type {
ProxyConfigArray,
ProxyConfigArrayItem,
Middleware,
ServerOptions,
} from 'webpack-dev-server';
import type { ProxyConfigArray, ProxyConfigArrayItem, Middleware, ServerOptions } from 'webpack-dev-server';
import type { Options } from '@ice/bundles/compiled/eslint-webpack-plugin';
import type { ForkTsCheckerWebpackPluginOptions } from '@ice/bundles/compiled/fork-ts-checker-webpack-plugin';
import type { UnpluginOptions, UnpluginContext } from '@ice/bundles/compiled/unplugin';
@ -53,8 +48,9 @@ export interface GetJsxTransformOptions {
interface SwcOptions {
removeExportExprs?: string[];
compilationConfig?: SwcCompilationConfig |
((source: string, id: string, options: GetJsxTransformOptions) => SwcCompilationConfig);
compilationConfig?:
| SwcCompilationConfig
| ((source: string, id: string, options: GetJsxTransformOptions) => SwcCompilationConfig);
keepExports?: string[] | { value: string[]; include?: (id: string) => boolean };
nodeTransform?: boolean;
}
@ -73,7 +69,12 @@ type Performance = Configuration['performance'];
interface TransformOptions {
isServer: boolean;
}
type Transform = (this: UnpluginContext, code: string, id: string, options: TransformOptions) => ReturnType<UnpluginOptions['transform']>;
type Transform = (
this: UnpluginContext,
code: string,
id: string,
options: TransformOptions,
) => ReturnType<UnpluginOptions['transform']>;
// Only support transform and transformInclude for now
interface TransformPlugin {
@ -131,10 +132,7 @@ export interface Config {
loaders?: (undefined | null | false | '' | 0 | RuleSetRule | '...')[];
plugins?: (
| PluginFunction
| WebpackPluginInstance
)[];
plugins?: (PluginFunction | WebpackPluginInstance)[];
alias?: Record<string, string | false>;
@ -144,9 +142,7 @@ export interface Config {
transforms?: Transform[];
middlewares?:
| ((middlewares: Middleware[], devServer: Server) => Middleware[])
| undefined;
middlewares?: ((middlewares: Middleware[], devServer: Server) => Middleware[]) | undefined;
proxy?: ProxyConfigArray;
@ -168,6 +164,8 @@ export interface Config {
enableCache?: boolean;
isServer?: boolean;
cacheDir?: string;
tsCheckerOptions?: ForkTsCheckerWebpackPluginOptions;
@ -259,4 +257,9 @@ export interface Config {
template?: string;
};
};
definitions?: Record<string, string | string[]>;
externalsPresets?: Configuration['externalsPresets'];
webpackTarget?: Configuration['target'];
}

View File

@ -45,13 +45,13 @@ const compilationPlugin = (options: Options): UnpluginOptions => {
} = options;
const { removeExportExprs, compilationConfig, keepExports, nodeTransform } = swcOptions;
const compileRegex = [...compileIncludes, ...COMPILE_DEPS].map((includeRule) => {
return includeRule instanceof RegExp ? includeRule : new RegExp(includeRule);
});
function isRouteEntry(id: string) {
const routes = getRoutesFile();
const matched = routes.find(route => {
return id.indexOf(route) > -1;
});

View File

@ -1,5 +1,18 @@
# Changelog
## 1.2.1
### Patch Changes
- 97cb2046: fix: use @ice/bundles instead of import webpack directly.
feat: support pass definitions for provide plugin.
- Updated dependencies [97cb2046]
- Updated dependencies [97cb2046]
- Updated dependencies [a0099df5]
- Updated dependencies [97cb2046]
- @ice/bundles@0.2.8
- @ice/shared-config@1.3.1
## 1.2.0
### Minor Changes

View File

@ -1,13 +1,14 @@
{
"name": "@ice/webpack-config",
"version": "1.2.0",
"version": "1.2.1",
"repository": "alibaba/ice",
"bugs": "https://github.com/alibaba/ice/issues",
"homepage": "https://v3.ice.work",
"type": "module",
"main": "./esm/index.js",
"exports": {
".": "./esm/index.js"
".": "./esm/index.js",
"./*": "./*"
},
"files": [
"esm",
@ -15,8 +16,8 @@
"*.d.ts"
],
"dependencies": {
"@ice/shared-config": "1.3.0",
"@ice/bundles": "0.2.7",
"@ice/shared-config": "1.3.1",
"@ice/bundles": "0.2.8",
"fast-glob": "^3.2.11",
"process": "^0.11.10"
},

View File

@ -34,6 +34,7 @@ interface GetWebpackConfigOptions {
getExpandedEnvs: () => Record<string, string>;
runtimeDefineVars?: Record<string, any>;
getRoutesFile?: () => string[];
isServer?: boolean;
}
enum JSMinifier {
@ -70,6 +71,7 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio
getExpandedEnvs,
runtimeDefineVars = {},
getRoutesFile,
isServer = false,
} = options;
const {
@ -110,14 +112,17 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio
polyfill,
enableRpx2Vw = true,
enableEnv = true,
definitions = {},
webpackTarget,
externalsPresets,
} = config;
const absoluteOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(rootDir, outputDir);
const dev = mode !== 'production';
const hashKey = hash === true ? 'hash:8' : (hash || '');
const aliasWithRoot = getAliasWithRoot(rootDir, alias);
const defineVars = getDefineVars(config.define, runtimeDefineVars, getExpandedEnvs, webpack);
const defineVarsWithRuntime = getDefineVars(config.define, runtimeDefineVars, getExpandedEnvs, webpack);
const lazyCompilationConfig = dev && experimental?.lazyCompilation ? {
lazyCompilation: {
test: (module: NormalModule) => {
@ -129,8 +134,7 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio
},
} : {};
// get compile plugins
const compilerWebpackPlugins = getCompilerPlugins(rootDir, config, 'webpack', { isServer: false });
const compilerWebpackPlugins = getCompilerPlugins(rootDir, config, 'webpack', { isServer });
const terserOptions: any = merge({
compress: {
ecma: 5,
@ -169,8 +173,11 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio
enableEnv,
getRoutesFile,
});
const webpackConfig = {
mode,
target: webpackTarget,
externalsPresets,
experiments: {
layers: true,
cacheUnaffected: true,
@ -284,11 +291,10 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio
}),
new webpack.ProvidePlugin({
process: require.resolve('process/browser'),
...definitions,
}),
new webpack.DefinePlugin({
...defineVars,
...runtimeDefineVars,
}),
// server don't need runtimeDefine
new webpack.DefinePlugin(isServer ? config.define : defineVarsWithRuntime),
assetsManifest && new AssetsManifestPlugin({
fileName: 'assets-manifest.json',
outputDir: path.join(rootDir, runtimeTmpDir),
@ -362,7 +368,6 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio
// 原因:[managedPaths](https://webpack.js.org/configuration/other-options/#managedpaths) 在 tnpm / cnpm 安装的情况下失效,导致持久缓存在处理 node_modules
// 通过指定 [immutablePaths](https://webpack.js.org/configuration/other-options/#immutablepaths) 进行兼容
// 依赖路径中同时包含包名和版本号即可满足 immutablePaths 的使用
// 通过安装后的 package.json 中是否包含 __npminstall_done 字段来判断是否为 tnpm / cnpm 安装模式
if (require('../package.json').__npminstall_done) {
const nodeModulesPath = path.join(rootDir, 'node_modules');
@ -431,6 +436,7 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio
bundler: webpack,
enableRpx2Vw,
};
return [configCss, configAssets, ...(configureWebpack || [])]
.reduce((result, next: ModifyWebpackConfig<Configuration, typeof webpack>) => next(result, ctx), webpackConfig);
}

View File

@ -1,5 +1,5 @@
diff --git a/dist/index.js b/dist/index.js
index 57955f085ab0ccf9cb514390a6d2472531a1e6c1..d333b82dcbc299c4580288955df54f1d77ff625b 100644
index 57955f085ab0ccf9cb514390a6d2472531a1e6c1..07bf7c4a7addf83ebbb13bd38e56e271244e9945 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -694,6 +694,7 @@ __export(src_exports, {
@ -31,7 +31,120 @@ index 57955f085ab0ccf9cb514390a6d2472531a1e6c1..d333b82dcbc299c4580288955df54f1d
// src/builtin-plugin/css-extract/index.ts
var import_binding11 = require("@rspack/binding");
var import_node_path3 = require("path");
@@ -20545,6 +20553,7 @@ module.exports = rspack;
@@ -13128,110 +13136,9 @@ var Watching = class {
};
// src/util/bindingVersionCheck.ts
-var import_node_fs3 = require("fs");
-var import_node_path11 = __toESM(require("path"));
-var NodePlatformArchToAbi = {
- android: {
- arm64: "",
- arm: "eabi"
- },
- win32: {
- x64: "msvc",
- ia32: "msvc",
- arm64: "msvc"
- },
- darwin: {
- x64: "",
- arm64: ""
- },
- freebsd: {
- x64: ""
- },
- linux: {
- x64: {
- musl: "musl",
- gnu: "gnu"
- },
- arm64: {
- musl: "musl",
- gnu: "gnu"
- },
- arm: "gnueabihf"
- }
-};
-function isMusl() {
- if (!process.report || typeof process.report.getReport !== "function") {
- try {
- const lddPath = require("child_process").execSync("which ldd").toString().trim();
- return (0, import_node_fs3.readFileSync)(lddPath, "utf8").includes("musl");
- } catch (e) {
- return true;
- }
- } else {
- const { glibcVersionRuntime } = process.report.getReport().header;
- return !glibcVersionRuntime;
- }
-}
-var BINDING_VERSION = require("@rspack/binding/package.json").version;
-var CORE_VERSION = require("../package.json").version;
-var getAddonPlatformArchAbi = () => {
- const { platform, arch } = process;
- let binding9 = "";
- binding9 += platform;
- const abi = NodePlatformArchToAbi[platform][arch];
- if (abi === void 0) return new Error(`unsupported cpu arch: ${arch}`);
- binding9 += `-${arch}`;
- if (typeof abi === "string") {
- binding9 += abi.length ? `-${abi}` : "";
- } else if (typeof abi === "object") {
- binding9 += `-${abi[isMusl() ? "musl" : "gnu"]}`;
- } else {
- return new Error(`unsupported abi: ${abi}`);
- }
- return binding9;
-};
-var result;
var checkVersion = () => {
- if (result !== void 0) {
- return result;
- }
- const platformArchAbi = getAddonPlatformArchAbi();
- if (platformArchAbi instanceof Error) {
- return result = platformArchAbi;
- }
- let ADDON_VERSION;
- try {
- const BINDING_PKG_DIR = import_node_path11.default.dirname(
- require.resolve("@rspack/binding/package.json")
- );
- const isLocal = (0, import_node_fs3.readdirSync)(BINDING_PKG_DIR).some(
- (item) => item === `rspack.${platformArchAbi}.node`
- );
- if (isLocal) {
- ADDON_VERSION = BINDING_VERSION;
- } else {
- ADDON_VERSION = require(require.resolve(`@rspack/binding-${platformArchAbi}/package.json`, {
- paths: [BINDING_PKG_DIR]
- })).version;
- }
- } catch (error) {
- if (error instanceof Error) {
- return result = new Error(
- `${error.toString()}. Maybe you forget to install the correct addon package ${`@rspack/binding-${platformArchAbi}`} or forget to build binding locally?`
- );
- }
- return result = new Error(error);
- }
- const isMatch = [CORE_VERSION, BINDING_VERSION, ADDON_VERSION].every(
- (v, _, arr) => v === arr[0]
- );
- if (!isMatch) {
- return result = new Error(
- `Unmatched version @rspack/core@${CORE_VERSION}, @rspack/binding@${BINDING_VERSION}, @rspack/binding-${platformArchAbi}@${ADDON_VERSION}.
-Rspack requires these versions to be the same or you may have installed the wrong version. Otherwise, Rspack may not work properly.`
- );
- }
- return result = null;
+ // Remove version check, ice framework will handle it.
+ return null;
};
// src/builtin-plugin/html-plugin/taps.ts
@@ -20545,6 +20452,7 @@ module.exports = rspack;
Compiler,
ContextReplacementPlugin,
CopyRspackPlugin,

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,8 @@ describe(`build ${example}`, () => {
expect(bundleContent.includes('__IS_NODE__')).toBe(false);
expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/favicon.ico`))).toBe(true);
expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/js/data-loader.js`))).toBe(true);
expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/index.html`))).toBe(true);
expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/blog.html`))).toBe(true);
const jsonContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build/assets-manifest.json`), 'utf-8');
expect(JSON.parse(jsonContent).pages.about.includes('js/framework.js')).toBeFalsy();
const dataLoaderPath = path.join(__dirname, `../../examples/${example}/build/js/data-loader.js`);
@ -69,6 +71,14 @@ describe(`build ${example}`, () => {
expect((await page.$$text('h2')).length).toEqual(0);
});
test('using "compat" html generating mode', async () => {
await buildFixture(example, {
config: 'compatHtml.config.mts',
});
expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/index.html`))).toBeTruthy();
expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/blog/index.html`))).toBeTruthy();
});
afterAll(async () => {
await browser.close();
});

View File

@ -620,11 +620,30 @@ export default defineConfig(() => ({
### htmlGenerating
- 类型:`boolean`
- 类型:`boolean | object`
- 默认值:`true`
如果产物不想生成 html可以设置为 `false`,在 SSG 开启的情况下,强制关闭 html 生成,将导致 SSG 失效。
传入 `true` 则与 `{}` 效果一致。
#### htmlGenerating.mode
- 类型: `'cleanUrl' | 'compat'`
- 默认值 `'cleanUrl'`
配置 HTML 生成文件的规则,避免在某些服务器下出现非首页内容刷新后 404 的情况。目前主要由两种,分别是:
- `cleanUrl` 生成的文件路径和路由一致。通常用于支持此模式的现代服务器,即自动省略 `.html` 后缀
- `compat` 生成兼容模式的路径文件,通常用于一些只能省略 `index.html` 的服务器
具体区别可以参照下表:
| Route | `/` | `/foo` | `/foo/bar` |
|------------|---------------|-------------------|-----------------------|
| `cleanUrl` | `/index.html` | `/foo.html` | `/foo/bar.html` |
| `compat` | `/index.html` | `/foo/index.html` | `/foo/bar/index.html` |
### plugins
- 类型:`PluginList<Config, OverwritePluginAPI>`