mirror of https://github.com/alibaba/ice.git
Feat/plugin rax compat (#262)
* feat: support inlineStyle option for plugin rax compat * fix: update pnpm lock yaml * refactor: rax-compat create-element and plugin rule * chore: remove some lint problem * chore: update pnpm lock * chore: update pnpm * feat: add warn for inline style
This commit is contained in:
parent
e42a9ba67a
commit
59aa271de1
|
|
@ -1,15 +1,22 @@
|
||||||
# @ice/plugin-rax-compat
|
# @ice/plugin-rax-compat
|
||||||
|
|
||||||
ice plugin for migrate `rax-app` project to `ice`.
|
ICE plugin for migrating `rax-app` project into `ICE`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
add plugin in `ice.config.ts`:
|
add plugin in `ice.config.ts`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import raxCompat from '@ice/plugin-rax-compat';
|
import compatRax from '@ice/plugin-rax-compat';
|
||||||
|
|
||||||
export default {
|
export default defineConfig({
|
||||||
plugins: [raxCompat()],
|
plugins: [compatRax(options)],
|
||||||
}
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- inlineStyle:
|
||||||
|
- Enable stylesheet loader to import css file.
|
||||||
|
- default to `false`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,13 @@
|
||||||
"!esm/**/*.map"
|
"!esm/**/*.map"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"rax-compat": "^0.1.0"
|
"consola": "^2.15.3",
|
||||||
|
"rax-compat": "^0.1.0",
|
||||||
|
"stylesheet-loader": "^0.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ice/types": "^1.0.0"
|
"@ice/types": "^1.0.0",
|
||||||
|
"@types/webpack": "^5.28.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "http",
|
"type": "http",
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { createRequire } from 'module';
|
import { createRequire } from 'module';
|
||||||
import type { Plugin } from '@ice/types';
|
import type { Plugin } from '@ice/types';
|
||||||
|
import type { RuleSetRule } from 'webpack';
|
||||||
|
import consola from 'consola';
|
||||||
|
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const plugin: Plugin = ({ onGetConfig }) => {
|
const alias = {
|
||||||
onGetConfig((config) => {
|
|
||||||
Object.assign(config.alias, {
|
|
||||||
// Add rax compat packages.
|
// Add rax compat packages.
|
||||||
rax: require.resolve('rax-compat'),
|
rax: require.resolve('rax-compat'),
|
||||||
'rax-children': require.resolve('rax-compat/children'),
|
'rax-children': require.resolve('rax-compat/children'),
|
||||||
|
|
@ -16,11 +16,56 @@ const plugin: Plugin = ({ onGetConfig }) => {
|
||||||
'rax-find-dom-node': require.resolve('rax-compat/find-dom-node'),
|
'rax-find-dom-node': require.resolve('rax-compat/find-dom-node'),
|
||||||
'rax-is-valid-element': require.resolve('rax-compat/is-valid-element'),
|
'rax-is-valid-element': require.resolve('rax-compat/is-valid-element'),
|
||||||
'rax-unmount-component-at-node': require.resolve('rax-compat/unmount-component-at-node'),
|
'rax-unmount-component-at-node': require.resolve('rax-compat/unmount-component-at-node'),
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => ({
|
const ruleSetStylesheet = {
|
||||||
name: '@ice/plugin-rax-compat',
|
test: /\.css$/i,
|
||||||
plugin,
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('stylesheet-loader'),
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
function getPlugin(options: CompatRaxOptions): Plugin {
|
||||||
|
return ({ onGetConfig }) => {
|
||||||
|
onGetConfig((config) => {
|
||||||
|
Object.assign(config.alias, alias);
|
||||||
|
if (options.inlineStyle) {
|
||||||
|
consola.warn('[WARN] Enabling inline style is not recommended.');
|
||||||
|
consola.warn(' It is recommended to use CSS modules (as default). Only allow old projects to migrate and use.');
|
||||||
|
config.configureWebpack ??= [];
|
||||||
|
config.configureWebpack.unshift((config) => {
|
||||||
|
const { rules } = config.module || {};
|
||||||
|
if (Array.isArray(rules)) {
|
||||||
|
for (let i = 0, l = rules.length; i < l; i++) {
|
||||||
|
const rule: RuleSetRule | any = rules[i];
|
||||||
|
// Find the css rule, that default to CSS Modules.
|
||||||
|
if (rule.test && rule.test.source.indexOf('.css') > -1) {
|
||||||
|
rule.test = /\.module\.css$/i;
|
||||||
|
rules[i] = {
|
||||||
|
test: /\.css$/i,
|
||||||
|
oneOf: [
|
||||||
|
rule,
|
||||||
|
ruleSetStylesheet,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompatRaxOptions {
|
||||||
|
inlineStyle?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (options: CompatRaxOptions | void) => ({
|
||||||
|
name: '@ice/plugin-rax-compat',
|
||||||
|
plugin: getPlugin(options || {}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import type {
|
||||||
ReactNode,
|
ReactNode,
|
||||||
RefObject,
|
RefObject,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { createElement as _createElement, useEffect, useRef, forwardRef } from 'react';
|
import { createElement as _createElement, useEffect, forwardRef } from 'react';
|
||||||
import { setupAppear } from 'appear-polyfill';
|
import { setupAppear } from 'appear-polyfill';
|
||||||
import { cached } from 'style-unit';
|
import { cached, convertUnit } from 'style-unit';
|
||||||
import { isFunction, isObject, isNumber } from './type';
|
import { isFunction, isObject, isNumber } from './type';
|
||||||
|
|
||||||
let appearSetup = false;
|
let appearSetup = false;
|
||||||
|
|
@ -18,8 +18,6 @@ function setupAppearOnce() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasOwn = {}.hasOwnProperty;
|
|
||||||
|
|
||||||
// https://github.com/alibaba/rax/blob/master/packages/driver-dom/src/index.js
|
// https://github.com/alibaba/rax/blob/master/packages/driver-dom/src/index.js
|
||||||
// opacity -> opa
|
// opacity -> opa
|
||||||
// fontWeight -> ntw
|
// fontWeight -> ntw
|
||||||
|
|
@ -55,19 +53,23 @@ export function createElement<P extends {
|
||||||
type: FunctionComponent<P>,
|
type: FunctionComponent<P>,
|
||||||
props?: Attributes & P | null,
|
props?: Attributes & P | null,
|
||||||
...children: ReactNode[]): ReactElement {
|
...children: ReactNode[]): ReactElement {
|
||||||
const { children: propsChildren, onAppear, onDisappear } = props || {};
|
|
||||||
const rest = Object.assign({}, props);
|
const rest = Object.assign({}, props);
|
||||||
|
const { children: propsChildren, onAppear, onDisappear } = rest;
|
||||||
delete rest.children;
|
delete rest.children;
|
||||||
delete rest.onAppear;
|
delete rest.onAppear;
|
||||||
delete rest.onDisappear;
|
delete rest.onDisappear;
|
||||||
|
|
||||||
// Compat for style unit.
|
// Compat for style unit.
|
||||||
rest.style = compatStyle(rest.style);
|
const compatStyleProps = compatStyle(rest.style);
|
||||||
|
if (compatStyleProps) {
|
||||||
|
rest.style = compatStyleProps;
|
||||||
|
}
|
||||||
|
|
||||||
rest.ref = props.ref || useRef(null);
|
// Create backend element.
|
||||||
const args = [type, rest as Attributes & P | null, propsChildren];
|
const args = [type, rest, propsChildren];
|
||||||
let element: any = _createElement.apply(null, args.concat(children));
|
let element: any = _createElement.apply(null, args.concat(children));
|
||||||
// Polyfill onAppear and onDisappear.
|
|
||||||
|
// Polyfill for appear and disappear event.
|
||||||
if (isFunction(onAppear) || isFunction(onDisappear)) {
|
if (isFunction(onAppear) || isFunction(onDisappear)) {
|
||||||
setupAppearOnce();
|
setupAppearOnce();
|
||||||
element = _createElement(forwardRef(AppearOrDisappear), {
|
element = _createElement(forwardRef(AppearOrDisappear), {
|
||||||
|
|
@ -82,19 +84,24 @@ export function createElement<P extends {
|
||||||
|
|
||||||
const isDimensionalProp = cached((prop: string) => !NON_DIMENSIONAL_REG.test(prop));
|
const isDimensionalProp = cached((prop: string) => !NON_DIMENSIONAL_REG.test(prop));
|
||||||
|
|
||||||
// Convert numeric value into rpx.
|
// Convert unit as driver-dom does.
|
||||||
// eg. width: 2px ->
|
// https://github.com/alibaba/rax/blob/master/packages/driver-dom/src/index.js#L346
|
||||||
function compatStyle(style?: object): any {
|
function compatStyle<S = object>(style?: S): S | void {
|
||||||
if (isObject(style)) {
|
if (isObject(style)) {
|
||||||
const result = {};
|
// Do not modify the original style object, copy results to another plain object.
|
||||||
|
const result = Object.create(null);
|
||||||
for (let key in style) {
|
for (let key in style) {
|
||||||
if (hasOwn.call(style, key)) {
|
const value = style[key];
|
||||||
// @ts-ignore
|
if (isNumber(value) && isDimensionalProp(key)) {
|
||||||
if (isNumber(style[key]) && isDimensionalProp(key)) result[key] = `${style[key]}rpx`;
|
// Transform rpx to vw.
|
||||||
|
result[key] = convertUnit(`${value}rpx`);
|
||||||
|
} else {
|
||||||
|
result[key] = convertUnit(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appear HOC Component.
|
// Appear HOC Component.
|
||||||
|
|
@ -106,6 +113,7 @@ function AppearOrDisappear(props: any, ref: RefObject<EventTarget>) {
|
||||||
|
|
||||||
function listen(eventName: string, handler: EventListenerOrEventListenerObject) {
|
function listen(eventName: string, handler: EventListenerOrEventListenerObject) {
|
||||||
if (isFunction(handler) && ref != null) {
|
if (isFunction(handler) && ref != null) {
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { current } = ref;
|
const { current } = ref;
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
|
|
|
||||||
3875
pnpm-lock.yaml
3875
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -38,11 +38,12 @@ async function checkVersionExists(pkg: string, version: string, distTag: string)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getVersionPrefix(version): string {
|
export function getVersionPrefix(version): string {
|
||||||
return isNaN(version[0]) ? version[0] : '';
|
return Number.isNaN(version[0]) ? version[0] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPackageInfos(distTag = ''): Promise<IPackageInfo[]> {
|
export async function getPackageInfos(distTag = ''): Promise<IPackageInfo[]> {
|
||||||
const packageInfos: IPackageInfo[] = [];
|
const packageInfos: IPackageInfo[] = [];
|
||||||
|
// eslint-disable-next-line no-negated-condition
|
||||||
if (!existsSync(TARGET_DIRECTORY)) {
|
if (!existsSync(TARGET_DIRECTORY)) {
|
||||||
console.log(`[ERROR] Directory ${TARGET_DIRECTORY} not exist!`);
|
console.log(`[ERROR] Directory ${TARGET_DIRECTORY} not exist!`);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue