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 for migrate `rax-app` project to `ice`. | ||||
| ICE plugin for migrating `rax-app` project into `ICE`. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| add plugin in `ice.config.ts`: | ||||
| 
 | ||||
| ```js | ||||
| import raxCompat from '@ice/plugin-rax-compat'; | ||||
| import compatRax from '@ice/plugin-rax-compat'; | ||||
| 
 | ||||
| export default { | ||||
|   plugins: [raxCompat()], | ||||
| } | ||||
| ``` | ||||
| export default defineConfig({ | ||||
|   plugins: [compatRax(options)], | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| ## Options | ||||
| 
 | ||||
| - inlineStyle:  | ||||
|   - Enable stylesheet loader to import css file. | ||||
|   - default to `false` | ||||
|    | ||||
|  |  | |||
|  | @ -17,10 +17,13 @@ | |||
|     "!esm/**/*.map" | ||||
|   ], | ||||
|   "dependencies": { | ||||
|     "rax-compat": "^0.1.0" | ||||
|     "consola": "^2.15.3", | ||||
|     "rax-compat": "^0.1.0", | ||||
|     "stylesheet-loader": "^0.9.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@ice/types": "^1.0.0" | ||||
|     "@ice/types": "^1.0.0", | ||||
|     "@types/webpack": "^5.28.0" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "http", | ||||
|  |  | |||
|  | @ -1,26 +1,71 @@ | |||
| import { createRequire } from 'module'; | ||||
| import type { Plugin } from '@ice/types'; | ||||
| import type { RuleSetRule } from 'webpack'; | ||||
| import consola from 'consola'; | ||||
| 
 | ||||
| const require = createRequire(import.meta.url); | ||||
| 
 | ||||
| const plugin: Plugin = ({ onGetConfig }) => { | ||||
|   onGetConfig((config) => { | ||||
|     Object.assign(config.alias, { | ||||
|       // Add rax compat packages.
 | ||||
|       rax: require.resolve('rax-compat'), | ||||
|       'rax-children': require.resolve('rax-compat/children'), | ||||
|       'rax-clone-element': require.resolve('rax-compat/clone-element'), | ||||
|       'rax-create-class': require.resolve('rax-compat/create-class'), | ||||
|       'rax-create-factory': require.resolve('rax-compat/create-factory'), | ||||
|       'rax-create-portal': require.resolve('rax-compat/create-portal'), | ||||
|       'rax-find-dom-node': require.resolve('rax-compat/find-dom-node'), | ||||
|       'rax-is-valid-element': require.resolve('rax-compat/is-valid-element'), | ||||
|       'rax-unmount-component-at-node': require.resolve('rax-compat/unmount-component-at-node'), | ||||
|     }); | ||||
|   }); | ||||
| const alias = { | ||||
|   // Add rax compat packages.
 | ||||
|   rax: require.resolve('rax-compat'), | ||||
|   'rax-children': require.resolve('rax-compat/children'), | ||||
|   'rax-clone-element': require.resolve('rax-compat/clone-element'), | ||||
|   'rax-create-class': require.resolve('rax-compat/create-class'), | ||||
|   'rax-create-factory': require.resolve('rax-compat/create-factory'), | ||||
|   'rax-create-portal': require.resolve('rax-compat/create-portal'), | ||||
|   'rax-find-dom-node': require.resolve('rax-compat/find-dom-node'), | ||||
|   'rax-is-valid-element': require.resolve('rax-compat/is-valid-element'), | ||||
|   'rax-unmount-component-at-node': require.resolve('rax-compat/unmount-component-at-node'), | ||||
| }; | ||||
| 
 | ||||
| export default () => ({ | ||||
| const ruleSetStylesheet = { | ||||
|   test: /\.css$/i, | ||||
|   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, | ||||
|   plugin: getPlugin(options || {}), | ||||
| }); | ||||
|  |  | |||
|  | @ -5,9 +5,9 @@ import type { | |||
|   ReactNode, | ||||
|   RefObject, | ||||
| } 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 { cached } from 'style-unit'; | ||||
| import { cached, convertUnit } from 'style-unit'; | ||||
| import { isFunction, isObject, isNumber } from './type'; | ||||
| 
 | ||||
| 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
 | ||||
| // opacity -> opa
 | ||||
| // fontWeight -> ntw
 | ||||
|  | @ -55,19 +53,23 @@ export function createElement<P extends { | |||
|   type: FunctionComponent<P>, | ||||
|   props?: Attributes & P | null, | ||||
|   ...children: ReactNode[]): ReactElement { | ||||
|   const { children: propsChildren, onAppear, onDisappear } = props || {}; | ||||
|   const rest = Object.assign({}, props); | ||||
|   const { children: propsChildren, onAppear, onDisappear } = rest; | ||||
|   delete rest.children; | ||||
|   delete rest.onAppear; | ||||
|   delete rest.onDisappear; | ||||
| 
 | ||||
|   // 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); | ||||
|   const args = [type, rest as Attributes & P | null, propsChildren]; | ||||
|   // Create backend element.
 | ||||
|   const args = [type, rest, propsChildren]; | ||||
|   let element: any = _createElement.apply(null, args.concat(children)); | ||||
|   // Polyfill onAppear and onDisappear.
 | ||||
| 
 | ||||
|   // Polyfill for appear and disappear event.
 | ||||
|   if (isFunction(onAppear) || isFunction(onDisappear)) { | ||||
|     setupAppearOnce(); | ||||
|     element = _createElement(forwardRef(AppearOrDisappear), { | ||||
|  | @ -82,19 +84,24 @@ export function createElement<P extends { | |||
| 
 | ||||
| const isDimensionalProp = cached((prop: string) => !NON_DIMENSIONAL_REG.test(prop)); | ||||
| 
 | ||||
| // Convert numeric value into rpx.
 | ||||
| // eg. width: 2px ->
 | ||||
| function compatStyle(style?: object): any { | ||||
| // Convert unit as driver-dom does.
 | ||||
| // https://github.com/alibaba/rax/blob/master/packages/driver-dom/src/index.js#L346
 | ||||
| function compatStyle<S = object>(style?: S): S | void { | ||||
|   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) { | ||||
|       if (hasOwn.call(style, key)) { | ||||
|         // @ts-ignore
 | ||||
|         if (isNumber(style[key]) && isDimensionalProp(key)) result[key] = `${style[key]}rpx`; | ||||
|       const value = style[key]; | ||||
|       if (isNumber(value) && isDimensionalProp(key)) { | ||||
|         // Transform rpx to vw.
 | ||||
|         result[key] = convertUnit(`${value}rpx`); | ||||
|       } else { | ||||
|         result[key] = convertUnit(value); | ||||
|       } | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|   return style; | ||||
| } | ||||
| 
 | ||||
| // Appear HOC Component.
 | ||||
|  | @ -106,6 +113,7 @@ function AppearOrDisappear(props: any, ref: RefObject<EventTarget>) { | |||
| 
 | ||||
|   function listen(eventName: string, handler: EventListenerOrEventListenerObject) { | ||||
|     if (isFunction(handler) && ref != null) { | ||||
|       // eslint-disable-next-line react-hooks/rules-of-hooks
 | ||||
|       useEffect(() => { | ||||
|         const { current } = ref; | ||||
|         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 { | ||||
|   return isNaN(version[0]) ? version[0] : ''; | ||||
|   return Number.isNaN(version[0]) ? version[0] : ''; | ||||
| } | ||||
| 
 | ||||
| export async function getPackageInfos(distTag = ''): Promise<IPackageInfo[]> { | ||||
|   const packageInfos: IPackageInfo[] = []; | ||||
|   // eslint-disable-next-line no-negated-condition
 | ||||
|   if (!existsSync(TARGET_DIRECTORY)) { | ||||
|     console.log(`[ERROR] Directory ${TARGET_DIRECTORY} not exist!`); | ||||
|   } else { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue