diff --git a/lerna.json b/lerna.json index fb43f9c26..4f9d02e1d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.2.32", + "version": "0.2.33", "npmClient": "yarn", "useWorkspaces": true, "command": { diff --git a/packages/mona-cli/package.json b/packages/mona-cli/package.json index 6b7a3214a..74e0156c1 100644 --- a/packages/mona-cli/package.json +++ b/packages/mona-cli/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-cli", - "version": "0.2.32", + "version": "0.2.33", "displayName": "mona", "description": "Merchant app's developing and building tools", "main": "./bin/mona", @@ -20,8 +20,8 @@ "author": "zhangxiaowei.chris@bytedance.com", "license": "MIT", "dependencies": { - "@bytedance/mona-service": "0.2.32", - "@bytedance/mona-shared": "0.2.32", + "@bytedance/mona-service": "0.2.33", + "@bytedance/mona-shared": "0.2.33", "chalk": "^4.1.2", "command-line-usage": "^6.1.1", "compare-version": "^0.1.2", diff --git a/packages/mona-clients/mona-client-mini/package.json b/packages/mona-clients/mona-client-mini/package.json index f6c2042d9..8c33af60b 100644 --- a/packages/mona-clients/mona-client-mini/package.json +++ b/packages/mona-clients/mona-client-mini/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-client-mini", - "version": "0.2.32", + "version": "0.2.33", "description": "miniapp for mona", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -21,8 +21,8 @@ "license": "MIT", "sideEffects": false, "dependencies": { - "@bytedance/mona": "0.2.32", - "@bytedance/mona-shared": "0.2.32", + "@bytedance/mona": "0.2.33", + "@bytedance/mona-shared": "0.2.33", "react-reconciler": "^0.26.2", "scheduler": "^0.20.2" }, diff --git a/packages/mona-clients/mona-client-mini/src/apis/api.ts b/packages/mona-clients/mona-client-mini/src/apis/api.ts index 2b3c54d5d..1c6a29d9f 100644 --- a/packages/mona-clients/mona-client-mini/src/apis/api.ts +++ b/packages/mona-clients/mona-client-mini/src/apis/api.ts @@ -41,7 +41,7 @@ export const getBackgroundAudioManager: BaseApis['getBackgroundAudioManager'] = export const createInnerAudioContext: BaseApis['createInnerAudioContext'] = tt.createInnerAudioContext; export const chooseVideo: BaseApis['chooseVideo'] = promisify(tt.chooseVideo); export const saveVideoToPhotoAlbum: BaseApis['saveVideoToPhotoAlbum'] = tt.saveVideoToPhotoAlbum; -export const createVideoContext: BaseApis['createVideoContext'] = promisify(tt.createVideoContext); +export const createVideoContext: BaseApis['createVideoContext'] = tt.createVideoContext; export const createLivePlayerContext: BaseApis['createLivePlayerContext'] = tt.createLivePlayerContext; export const preloadVideo: BaseApis['preloadVideo'] = promisify(tt.preloadVideo); export const createCameraContext: BaseApis['createCameraContext'] = tt.createCameraContext; diff --git a/packages/mona-clients/mona-client-plugin/package.json b/packages/mona-clients/mona-client-plugin/package.json index 0556f045e..7315948f4 100644 --- a/packages/mona-clients/mona-client-plugin/package.json +++ b/packages/mona-clients/mona-client-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-client-plugin", - "version": "0.2.32", + "version": "0.2.33", "description": "plugin for mona", "main": "./dist/index.js", "files": [ @@ -17,10 +17,10 @@ "mona" ], "dependencies": { - "@bytedance/mona": "0.2.32", - "@bytedance/mona-client-web": "0.2.32", - "@bytedance/mona-plugin-events": "0.2.32", - "@bytedance/mona-shared": "0.2.32" + "@bytedance/mona": "0.2.33", + "@bytedance/mona-client-web": "0.2.33", + "@bytedance/mona-plugin-events": "0.2.33", + "@bytedance/mona-shared": "0.2.33" }, "peerDependencies": { "react": "^17.0.2", diff --git a/packages/mona-clients/mona-client-web/package.json b/packages/mona-clients/mona-client-web/package.json index a2c5171fd..c82d6fef1 100644 --- a/packages/mona-clients/mona-client-web/package.json +++ b/packages/mona-clients/mona-client-web/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-client-web", - "version": "0.2.32", + "version": "0.2.33", "description": "web for mona", "main": "./dist/index.js", "files": [ @@ -19,16 +19,15 @@ "mona" ], "dependencies": { - "@bytedance/mona": "0.2.32", - "@bytedance/mona-shared": "0.2.32", - "ahooks": "^3.7.0", - "classnames": "^2.3.1", - "copyfiles": "^2.4.1" + "@bytedance/mona": "0.2.33", + "@bytedance/mona-shared": "0.2.33", + "ahooks": "^3.7.0" }, "devDependencies": { "@types/react-dom": "^17.0.2", "@types/react-router": "^5.1.17", "@types/react-router-dom": "^5.3.1", + "copyfiles": "^2.4.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-router-dom": "^5.2.0" diff --git a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Checkbox.spec.tsx.snap b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Checkbox.spec.tsx.snap index 4afd9d428..036bbd76c 100644 --- a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Checkbox.spec.tsx.snap +++ b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Checkbox.spec.tsx.snap @@ -62,7 +62,7 @@ LoadedCheerio { class="wrapper" >
+ "0":
@@ -66,7 +64,7 @@ LoadedCheerio { class="wrapper" >
+ "0":
, diff --git a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Radio.spec.tsx.snap b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Radio.spec.tsx.snap index dab0dacbe..c309dad20 100644 --- a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Radio.spec.tsx.snap +++ b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/Radio.spec.tsx.snap @@ -10,7 +10,7 @@ LoadedCheerio { class="wrapper" >
, + "0":
, "_root": LoadedCheerio { "0": Document { "children": Array [ diff --git a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/RichText.spec.tsx.snap b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/RichText.spec.tsx.snap index e3769a5e7..b4a49470c 100644 --- a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/RichText.spec.tsx.snap +++ b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/RichText.spec.tsx.snap @@ -39,9 +39,7 @@ LoadedCheerio { exports[`web component: RichText should render correctly 1`] = ` LoadedCheerio { - "0":
, + "0":
, "_root": LoadedCheerio { "0": Document { "children": Array [ diff --git a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/View.spec.tsx.snap b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/View.spec.tsx.snap index 23ed26f0c..92acf71f7 100644 --- a/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/View.spec.tsx.snap +++ b/packages/mona-clients/mona-client-web/src/__tests__/components/__snapshots__/View.spec.tsx.snap @@ -41,9 +41,7 @@ LoadedCheerio { exports[`web component: View should render correctly 1`] = ` LoadedCheerio { - "0":
, + "0":
, "_root": LoadedCheerio { "0": Document { "children": Array [ diff --git a/packages/mona-clients/mona-client-web/src/apis/api.ts b/packages/mona-clients/mona-client-web/src/apis/api.ts index 75bcfc278..c193a69e1 100644 --- a/packages/mona-clients/mona-client-web/src/apis/api.ts +++ b/packages/mona-clients/mona-client-web/src/apis/api.ts @@ -4,7 +4,7 @@ import { createCanvasContext as originCreateCanvasContext, canvasToTempFilePath as originCanvasToTempFilePath, } from './Canvas'; -import { promisify } from '@bytedance/mona-shared'; +import { promisify } from '@bytedance/mona-shared/dist/promisify'; import { webChooseImage, diff --git a/packages/mona-clients/mona-client-web/src/apis/components/Masking/index.tsx b/packages/mona-clients/mona-client-web/src/apis/components/Masking/index.tsx index 351ac4714..da6fe1de4 100644 --- a/packages/mona-clients/mona-client-web/src/apis/components/Masking/index.tsx +++ b/packages/mona-clients/mona-client-web/src/apis/components/Masking/index.tsx @@ -1,7 +1,6 @@ import React from 'react'; -import cs from 'classnames'; import './index.module.less'; -export function Masking({ onHandle, className }: { onHandle: () => void; className?: string }): JSX.Element { - return
; +export function Masking({ onHandle, className = '' }: { onHandle: () => void; className?: string }): JSX.Element { + return
; } diff --git a/packages/mona-clients/mona-client-web/src/apis/components/NavBar/index.tsx b/packages/mona-clients/mona-client-web/src/apis/components/NavBar/index.tsx index cc1bb9095..e052e16ec 100644 --- a/packages/mona-clients/mona-client-web/src/apis/components/NavBar/index.tsx +++ b/packages/mona-clients/mona-client-web/src/apis/components/NavBar/index.tsx @@ -1,5 +1,4 @@ import React, { FC } from 'react'; -import cs from 'classnames'; import './index.module.less'; interface NavBarProps { @@ -13,7 +12,7 @@ interface NavBarProps { } export const NavBar: FC = props => ( -
+
{props.left ? ( props.left diff --git a/packages/mona-clients/mona-client-web/src/apis/util.ts b/packages/mona-clients/mona-client-web/src/apis/util.ts index 3711442b9..809badb9f 100644 --- a/packages/mona-clients/mona-client-web/src/apis/util.ts +++ b/packages/mona-clients/mona-client-web/src/apis/util.ts @@ -1,4 +1,4 @@ -import { formatPath } from '@bytedance/mona-shared'; +import formatPath from '@bytedance/mona-shared/dist/formatPath'; import { GetImageInfoSuccessCallbackArgs, RequestTask, @@ -399,7 +399,7 @@ export const webNavigateTo: OriginApis['navigateTo'] = options => { let errMsg: string; try { errMsg = 'navigateTo:ok'; - const monaHistory = window.__mona_history; + const monaHistory = window.__mona_history || history; if (options.url.startsWith('..')) { monaHistory.push(formatPath(options.url, monaHistory.location.pathname)); } else { @@ -417,7 +417,7 @@ export const webRedirectTo: OriginApis['redirectTo'] = options => { let errMsg: string; try { errMsg = 'redirectTo:ok'; - const monaHistory = window.__mona_history; + const monaHistory = window.__mona_history || history; monaHistory.replace(formatPath(options.url, monaHistory.location.pathname)); options.success?.({ errMsg }); } catch (err) { @@ -435,9 +435,10 @@ export const webSwitchTab: OriginApis['switchTab'] = ({ url, success, fail, comp export const webNavigateBack: OriginApis['navigateBack'] = (options = {}) => { let errMsg: string; try { + const monaHistory = window.__mona_history || history; errMsg = 'navigateBack:ok'; const delta = options.delta || 1; - history.go(-delta); + monaHistory.go(-delta); options.success?.({ errMsg }); } catch (err) { errMsg = `navigateBack:fail${err}`; diff --git a/packages/mona-clients/mona-client-web/src/components/Checkbox/index.tsx b/packages/mona-clients/mona-client-web/src/components/Checkbox/index.tsx index 26515c02e..72767c2c1 100644 --- a/packages/mona-clients/mona-client-web/src/components/Checkbox/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Checkbox/index.tsx @@ -1,21 +1,12 @@ import React, { useState, useEffect, useContext, useRef } from 'react'; import { CheckboxProps } from '@bytedance/mona'; -import cs from 'classnames'; import { CheckboxGroupContext } from '../CheckboxGroup'; import styles from './index.module.less'; import { useHandlers } from '../hooks'; import { formatMouseEvent } from '../utils'; -const Checkbox: React.FC = (props) => { - const { - value, - disabled, - checked, - color = '#F85959', - children, - id, - ...restProps - } = props; +const Checkbox: React.FC = props => { + const { value, disabled, checked, color = '#F85959', children, id, ...restProps } = props; const group = useContext(CheckboxGroupContext); const orderRef = useRef(-1); @@ -31,39 +22,39 @@ const Checkbox: React.FC = (props) => { group?.toggleChecked(orderRef.current, newIsChecked, formatMouseEvent({ event: e, type: 'change' })); } onClick(e); - } - + }; + // don't change order of useEffects, the order is important useEffect(() => { setIsChecked(checked); if (orderRef.current >= 0) { group?.toggleChecked(orderRef.current, checked); } - }, [checked]) + }, [checked]); useEffect(() => { orderRef.current = group ? group?.initValue(value, checked, () => setIsChecked(false)) : -1; - }, []) + }, []); useEffect(() => { if (orderRef.current >= 0) { group?.changeValue(orderRef.current, value); } - }, [value]) + }, [value]); return ( -
+
-
+
{children}
- ) -} + ); +}; export default Checkbox; diff --git a/packages/mona-clients/mona-client-web/src/components/Icon/index.tsx b/packages/mona-clients/mona-client-web/src/components/Icon/index.tsx index 7e1379ee3..ebaedca58 100644 --- a/packages/mona-clients/mona-client-web/src/components/Icon/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Icon/index.tsx @@ -1,18 +1,17 @@ import React from 'react'; import { IconProps } from '@bytedance/mona'; -import cs from 'classnames'; import styles from './index.module.less'; import { useHandlers } from '../hooks'; -const Icon: React.FC = (props) => { +const Icon: React.FC = props => { const { children, type, size = 24, color, ...restProps } = props; const { handleClassName, ...handleProps } = useHandlers(restProps); return (
- +
- ) -} + ); +}; export default Icon; diff --git a/packages/mona-clients/mona-client-web/src/components/Image/index.tsx b/packages/mona-clients/mona-client-web/src/components/Image/index.tsx index e2429a85a..20fdbbe1d 100644 --- a/packages/mona-clients/mona-client-web/src/components/Image/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Image/index.tsx @@ -1,13 +1,20 @@ import React, { useContext, useEffect, useRef, useState } from 'react'; import { ImageProps } from '@bytedance/mona'; -import cs from 'classnames'; import { ScrollViewContext } from '../ScrollView'; import styles from './index.module.less'; import { useHandlers } from '../hooks'; import { formatSyntheticEvent } from '../utils'; -const ImageComponent: React.FC = ({ children, src, mode = 'scaleToFill', lazyLoad = false, onError, onLoad, ...restProps }) => { - const { handleClassName, ...handlerProps} = useHandlers(restProps); +const ImageComponent: React.FC = ({ + children, + src, + mode = 'scaleToFill', + lazyLoad = false, + onError, + onLoad, + ...restProps +}) => { + const { handleClassName, ...handlerProps } = useHandlers(restProps); const [url, setUrl] = useState(''); const [load, setLoad] = useState(!lazyLoad); const ref = useRef(null); @@ -20,13 +27,13 @@ const ImageComponent: React.FC = ({ children, src, mode = 'scaleToFi if (typeof onLoad === 'function') { onLoad(formatSyntheticEvent({ event: e })); } - } + }; const handleError = (e: React.SyntheticEvent) => { if (typeof onError === 'function') { onError(formatSyntheticEvent({ event: e })); } - } + }; // only run when init useEffect(() => { @@ -38,27 +45,32 @@ const ImageComponent: React.FC = ({ children, src, mode = 'scaleToFi const rect = ref.current?.getBoundingClientRect(); const top = rect?.top || 0; const left = rect?.left || 0; - if ((offsetTop + clientHeight) >= top && (offsetLeft + clientWidth) >= left) { + if (offsetTop + clientHeight >= top && offsetLeft + clientWidth >= left) { loadedRef.current = true; setLoad(true); } } - } - + }; + if (lazyLoad) { context?.registerScrollCallback(callback); } return () => { context?.unregisterScrollCallback(callback); - } - }, [lazyLoad]) - + }; + }, [lazyLoad]); + return (
{load ? : null} - {url ?
: null} + {url ? ( +
+ ) : null}
- ) -} + ); +}; export default ImageComponent; diff --git a/packages/mona-clients/mona-client-web/src/components/Link/index.tsx b/packages/mona-clients/mona-client-web/src/components/Link/index.tsx index b5d6a9f16..38db26afe 100644 --- a/packages/mona-clients/mona-client-web/src/components/Link/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Link/index.tsx @@ -1,4 +1,4 @@ -import { formatPath } from '@bytedance/mona-shared'; +import formatPath from '@bytedance/mona-shared/dist/formatPath'; import React from 'react'; import { Link as RouteLink } from 'react-router-dom'; diff --git a/packages/mona-clients/mona-client-web/src/components/Progress/index.tsx b/packages/mona-clients/mona-client-web/src/components/Progress/index.tsx index 719f41597..060fae9b9 100644 --- a/packages/mona-clients/mona-client-web/src/components/Progress/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Progress/index.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useRef, useState } from 'react'; import { ProgressProps } from '@bytedance/mona'; -import cs from 'classnames'; import styles from './index.module.less'; import { useHandlers } from '../hooks'; @@ -8,7 +7,7 @@ function format(percent: number) { return percent < 0 ? 0 : percent > 100 ? 100 : percent; } -const Progress: React.FC = (props) => { +const Progress: React.FC = props => { const { percent = 0, strokeWidth = 6, @@ -34,20 +33,32 @@ const Progress: React.FC = (props) => { setP(0); setTimeout(() => { gapRef.current = format(percent); - setP(format(percent)) - }, 0) + setP(format(percent)); + }, 0); } prevRef.current = format(percent); - }, [percent]) + }, [percent]); const { handleClassName, ...handleProps } = useHandlers(restProps); // const gap = percent - prevRef.current; - + return ( -
-
+
+
- ) -} + ); +}; export default Progress; diff --git a/packages/mona-clients/mona-client-web/src/components/Radio/index.tsx b/packages/mona-clients/mona-client-web/src/components/Radio/index.tsx index 4ffc0a847..37a8222cd 100644 --- a/packages/mona-clients/mona-client-web/src/components/Radio/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Radio/index.tsx @@ -1,21 +1,12 @@ import React, { useState, useEffect, useContext, useRef } from 'react'; import { RadioProps } from '@bytedance/mona'; -import cs from 'classnames'; import { RadioGroupContext } from '../RadioGroup'; import styles from './index.module.less'; import { useHandlers } from '../hooks'; import { formatMouseEvent } from '../utils'; -const Radio: React.FC = (props) => { - const { - value, - disabled, - checked, - color = '#F85959', - children, - id, - ...restProps - } = props; +const Radio: React.FC = props => { + const { value, disabled, checked, color = '#F85959', children, id, ...restProps } = props; const group = useContext(RadioGroupContext); const orderRef = useRef(-1); @@ -31,39 +22,39 @@ const Radio: React.FC = (props) => { group?.toggleChecked(orderRef.current, newIsChecked, formatMouseEvent({ event: e, type: 'change' })); } onClick(e); - } - + }; + // don't change order of useEffects, the order is important useEffect(() => { setIsChecked(checked); if (orderRef.current >= 0) { group?.toggleChecked(orderRef.current, checked); } - }, [checked]) + }, [checked]); useEffect(() => { orderRef.current = group ? group?.initValue(value, checked, () => setIsChecked(false)) : -1; - }, []) + }, []); useEffect(() => { if (orderRef.current >= 0) { group?.changeValue(orderRef.current, value); } - }, [value]) + }, [value]); return ( -
+
-
+
{children}
- ) -} + ); +}; export default Radio; diff --git a/packages/mona-clients/mona-client-web/src/components/Swiper/index.tsx b/packages/mona-clients/mona-client-web/src/components/Swiper/index.tsx index c5ebd5fff..53a2b825c 100644 --- a/packages/mona-clients/mona-client-web/src/components/Swiper/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Swiper/index.tsx @@ -1,7 +1,6 @@ // TODO: rewrite this component import React, { useEffect, useRef } from 'react'; import { SwiperProps } from '@bytedance/mona'; -import cs from 'classnames'; import styles from './index.module.less'; import { useHandlers } from '../hooks'; import { useSlide, useTouch } from './hooks'; @@ -90,13 +89,13 @@ const Swiper: React.FC = props => { ref={wrapperRef} onTouchStart={handleTouchStart} onTouchMove={handleTouchMove} - className={cs(vertical ? styles['vertical-wrapper'] : styles.wrapper)} + className={vertical ? styles['vertical-wrapper'] : styles.wrapper} style={{ transitionDuration: '0ms', transform: 'translate3d(10px, 0px, 0px)' }} > {children}
{indicatorDots && ( -
+
{(function () { const result = []; for (let i = 0; i < total; i++) { @@ -105,7 +104,7 @@ const Swiper: React.FC = props => { className={styles.dot} style={{ backgroundColor: activeIndex === i ? indicatorActiveColor : indicatorColor }} key={i} - > + >, ); } return result; diff --git a/packages/mona-clients/mona-client-web/src/components/Switch/index.tsx b/packages/mona-clients/mona-client-web/src/components/Switch/index.tsx index 455eca256..d1d3be3e0 100644 --- a/packages/mona-clients/mona-client-web/src/components/Switch/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/Switch/index.tsx @@ -1,50 +1,48 @@ import React, { useCallback, useEffect, useState } from 'react'; -import cs from 'classnames'; import styles from './index.module.less'; import { SwitchProps } from '@bytedance/mona'; import { useHandlers } from '../hooks'; import { useFormContext } from '../Form/hooks'; -const Switch: React.FC = (props) => { +const Switch: React.FC = props => { const { children, id, disabled, name = '', color = '#F85959', checked, type = 'switch', ...restProps } = props; - const { handleClassName, onClick, ...handlerProps} = useHandlers(restProps); + const { handleClassName, onClick, ...handlerProps } = useHandlers(restProps); const [isChecked, setIsChecked] = useState(checked); useEffect(() => { setIsChecked(checked); - }, [checked]) + }, [checked]); const handleClick = (e: React.MouseEvent) => { const newIsChecked = !isChecked; setIsChecked(newIsChecked); onClick(e); - } + }; const reset = useCallback(() => setIsChecked(false), []); useFormContext(name, isChecked, reset); return (
- { - type === 'checkbox' ? ( -
+ {type === 'checkbox' ? ( +
+ +
+ ) : ( +
+
+
- ) : ( -
-
- - -
- - {children} - -
- ) - } + {children} +
+ )}
- ) -} + ); +}; export default Switch; diff --git a/packages/mona-clients/mona-client-web/src/components/TabBar/index.tsx b/packages/mona-clients/mona-client-web/src/components/TabBar/index.tsx index 79a2cf601..f2627f3b5 100644 --- a/packages/mona-clients/mona-client-web/src/components/TabBar/index.tsx +++ b/packages/mona-clients/mona-client-web/src/components/TabBar/index.tsx @@ -1,5 +1,4 @@ import React, { FC } from 'react'; -import cs from 'classnames'; import { useBadge, useSelectTab, useTabProps, useToggleDotShow, useToggleShow } from './utils'; import styles from './index.module.less'; @@ -14,7 +13,7 @@ export type TabBarProps = { selectedIconPath?: string; text: string; }[]; -} +}; function calcBorderStyle(color?: 'black' | 'white') { if (['black', 'white'].indexOf(color || '') === -1) { @@ -23,20 +22,26 @@ function calcBorderStyle(color?: 'black' | 'white') { return color; } - const TabBar: FC<{ tab?: TabBarProps }> = ({ tab: rawTab }) => { const { tab } = useTabProps(rawTab); const { currentIndex, setCurrent } = useSelectTab(tab); - const { badges } = useBadge() - const { show, withAnimation } = useToggleShow() + const { badges } = useBadge(); + const { show, withAnimation } = useToggleShow(); const { dotIndexs } = useToggleDotShow(); - if ((!tab || tab.list.length <= 0)) { - return null + if (!tab || tab.list.length <= 0) { + return null; } return ( -
+
{tab.list.map((v, idx) => (
= ({ tab: rawTab }) => { style={{ color: tab?.color || 'black' }} >
- - { dotIndexs.indexOf(idx) !== -1 && } - { badges[idx] && {badges[idx].length > 3 ? '...' : badges[idx] } } + + {dotIndexs.indexOf(idx) !== -1 && } + {badges[idx] && {badges[idx].length > 3 ? '...' : badges[idx]}}
{v.text} @@ -61,4 +63,4 @@ const TabBar: FC<{ tab?: TabBarProps }> = ({ tab: rawTab }) => { ); }; -export default TabBar; \ No newline at end of file +export default TabBar; diff --git a/packages/mona-clients/mona-client-web/src/components/TabBar/utils.tsx b/packages/mona-clients/mona-client-web/src/components/TabBar/utils.tsx index dc6c46f33..700dd567d 100644 --- a/packages/mona-clients/mona-client-web/src/components/TabBar/utils.tsx +++ b/packages/mona-clients/mona-client-web/src/components/TabBar/utils.tsx @@ -1,5 +1,5 @@ import { redirectTo } from '../../apis/api'; -import { formatPath } from '@bytedance/mona-shared'; +import formatPath from '@bytedance/mona-shared/dist/formatPath'; import { BaseApis } from '@bytedance/mona'; import EventEmitter from '../../EventEmitter'; import { useHistory } from 'react-router'; diff --git a/packages/mona-clients/mona-client-web/src/components/hooks.ts b/packages/mona-clients/mona-client-web/src/components/hooks.ts index f3e1907a5..ff29c3609 100644 --- a/packages/mona-clients/mona-client-web/src/components/hooks.ts +++ b/packages/mona-clients/mona-client-web/src/components/hooks.ts @@ -1,6 +1,5 @@ import { useState, useRef, useEffect } from 'react'; import { BaseProps, HoverProps, Touch } from '@bytedance/mona'; -import cs from 'classnames'; import { formatMouseEvent, formatTouchEvent, formatTransitionEvent, formatAnimationEvent } from './utils'; const LONG_DURATION = 350; @@ -48,7 +47,7 @@ export function useHandlers(props: BaseProps & HoverProps) { } = props; const [isHover, setIsHover] = useState(false); - const timersRef = useRef[]>([]) + const timersRef = useRef[]>([]); const hoverRef = useRef(false); const shouldEmitLongEventRef = useRef(false); @@ -56,19 +55,19 @@ export function useHandlers(props: BaseProps & HoverProps) { timersRef.current.push( setTimeout(() => { callback(); - }, time) - ) - } + }, time), + ); + }; const stop = () => { hoverRef.current = false; delay(() => { hoverClassName && isHover && setIsHover(false); - }, hoverStayTime) - } + }, hoverStayTime); + }; - useEffect(() => () => timersRef.current.forEach(t => clearTimeout(t)), []) + useEffect(() => () => timersRef.current.forEach(t => clearTimeout(t)), []); const handleTouchStart = (e: React.TouchEvent) => { hoverRef.current = true; @@ -76,22 +75,22 @@ export function useHandlers(props: BaseProps & HoverProps) { delay(() => { hoverClassName && hoverRef.current && setIsHover(true); - }, hoverStartTime) + }, hoverStartTime); delay(() => { // simulate long press if (hoverRef.current) { shouldEmitLongEventRef.current = true; } - }, LONG_DURATION) + }, LONG_DURATION); - const event = formatTouchEvent({ event: e }) + const event = formatTouchEvent({ event: e }); isFunc(onTouchStart) && onTouchStart(event); if (isFunc(catchTouchStart)) { e.stopPropagation(); - catchTouchStart(event) - }; - } + catchTouchStart(event); + } + }; const handleTouchMove = (e: React.TouchEvent) => { stop(); @@ -102,7 +101,7 @@ export function useHandlers(props: BaseProps & HoverProps) { e.stopPropagation(); catchTouchMove(event); } - } + }; const handleTouchEnd = (e: React.TouchEvent) => { stop(); @@ -114,45 +113,45 @@ export function useHandlers(props: BaseProps & HoverProps) { catchTouchEnd(event); } if (shouldEmitLongEventRef.current) { - const longTapEvent = formatTouchEvent({ event: e, type: 'longtap' }) + const longTapEvent = formatTouchEvent({ event: e, type: 'longtap' }); isFunc(onLongTap) && onLongTap(longTapEvent); if (isFunc(catchLongTap)) { e.stopPropagation(); catchLongTap(longTapEvent); } - const longPressEvent = formatTouchEvent({ event: e, type: 'longpress' }) + const longPressEvent = formatTouchEvent({ event: e, type: 'longpress' }); if (isFunc(onLongPress)) { onLongPress(longPressEvent); } - if(isFunc(catchLongPress)) { + if (isFunc(catchLongPress)) { e.stopPropagation(); catchLongPress(longPressEvent); } } - } + }; const handleTouchCancel = (e: React.TouchEvent) => { stop(); - + const event = formatTouchEvent({ event: e }); isFunc(onTouchCancel) && onTouchCancel(event); if (isFunc(catchTouchCancel)) { e.stopPropagation(); catchTouchCancel(event); } - } + }; const handleTap = (e: React.MouseEvent) => { // if longPressEvent already emited, this event will not emit if (!(shouldEmitLongEventRef.current && isFunc(onLongPress))) { const event = formatMouseEvent({ event: e, type: 'tap' }); isFunc(onTap) && onTap(event); - if(isFunc(catchTap)) { + if (isFunc(catchTap)) { e.stopPropagation(); - catchTap(event) + catchTap(event); } } - } + }; const handleTransitionEnd = (e: React.TransitionEvent) => { const event = formatTransitionEvent({ event: e }); @@ -161,7 +160,7 @@ export function useHandlers(props: BaseProps & HoverProps) { e.stopPropagation(); catchTransitionEnd(event); } - } + }; const handleAnimationStart = (e: React.AnimationEvent) => { const event = formatAnimationEvent({ event: e }); @@ -170,7 +169,7 @@ export function useHandlers(props: BaseProps & HoverProps) { e.stopPropagation(); catchAnimationStart(event); } - } + }; const handleAnimationEnd = (e: React.AnimationEvent) => { const event = formatAnimationEvent({ event: e }); @@ -179,7 +178,7 @@ export function useHandlers(props: BaseProps & HoverProps) { e.stopPropagation(); catchAnimationEnd(event); } - } + }; const handleAnimationIteration = (e: React.AnimationEvent) => { const event = formatAnimationEvent({ event: e }); @@ -188,10 +187,14 @@ export function useHandlers(props: BaseProps & HoverProps) { e.stopPropagation(); catchAnimationIteration(event); } - } - - const handleClassName = (name?: string | string[]) => cs(name, className, { [hoverClassName]: hoverClassName && isHover }) + }; + const handleClassName = (name?: string | string[]) => { + if (Array.isArray(name)) { + name = name.join(' '); + } + return `${name ?? ''} ${className ?? ''} ${hoverClassName && isHover ? hoverClassName : ''} `.trim() || undefined; + }; return { onClick: handleTap, @@ -207,5 +210,5 @@ export function useHandlers(props: BaseProps & HoverProps) { // onTouchForceChange: undefined, handleClassName, ...restProps, - } -} \ No newline at end of file + }; +} diff --git a/packages/mona-clients/mona-client-web/src/createWebApp.tsx b/packages/mona-clients/mona-client-web/src/createWebApp.tsx index 6c18ea717..7a24f8ba2 100644 --- a/packages/mona-clients/mona-client-web/src/createWebApp.tsx +++ b/packages/mona-clients/mona-client-web/src/createWebApp.tsx @@ -4,11 +4,13 @@ import ReactDOM from 'react-dom'; import { BrowserRouter, Switch, Route, Redirect, useHistory } from 'react-router-dom'; import NavBar from './components/NavBar'; import TabBar from './components/TabBar'; -import { formatPath, parseSearch, GLOBAL_LIFECYCLE_STORE } from '@bytedance/mona-shared'; +import formatPath from '@bytedance/mona-shared/dist/formatPath'; +import { GLOBAL_LIFECYCLE_STORE } from '@bytedance/mona-shared/dist/constants'; +import { parseSearch } from '@bytedance/mona-shared/dist/search'; export const WrapperComponent: React.FC<{ title: string }> = ({ children, title }) => { document.title = title || 'Mona Web'; - + return <>{children}; }; diff --git a/packages/mona-clients/mona-client-web/src/createWebAppEvent.tsx b/packages/mona-clients/mona-client-web/src/createWebAppEvent.tsx index b3af52ea5..bf6ea2f01 100644 --- a/packages/mona-clients/mona-client-web/src/createWebAppEvent.tsx +++ b/packages/mona-clients/mona-client-web/src/createWebAppEvent.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { LifecycleContext, AppLifecycleGlobalContext, AppLifecycle } from '@bytedance/mona'; -import { isClassComponent, GLOBAL_LIFECYCLE_STORE } from '@bytedance/mona-shared'; +import { isClassComponent } from '@bytedance/mona-shared/dist/reactNode'; +import { GLOBAL_LIFECYCLE_STORE } from '@bytedance/mona-shared/dist/constants'; export function createAppLifeCycle(Component: React.ComponentType) { const appLifecycleContext = new LifecycleContext(); diff --git a/packages/mona-clients/mona-client-web/src/createWebPage.tsx b/packages/mona-clients/mona-client-web/src/createWebPage.tsx index 357d81092..93ecd3041 100644 --- a/packages/mona-clients/mona-client-web/src/createWebPage.tsx +++ b/packages/mona-clients/mona-client-web/src/createWebPage.tsx @@ -1,5 +1,7 @@ import React from 'react'; -import { isClassComponent, parseSearch } from '@bytedance/mona-shared'; +import { isClassComponent } from '@bytedance/mona-shared/dist/reactNode'; +import { parseSearch } from '@bytedance/mona-shared/dist/search'; + import { LifecycleContext, PageLifecycleGlobalContext, PageLifecycle } from '@bytedance/mona'; export function createPageLifecycle(Component: React.ComponentType) { diff --git a/packages/mona-clients/mona-client-web/src/hooks/useRequest.ts b/packages/mona-clients/mona-client-web/src/hooks/useRequest.ts index c64a734e5..8effcab92 100644 --- a/packages/mona-clients/mona-client-web/src/hooks/useRequest.ts +++ b/packages/mona-clients/mona-client-web/src/hooks/useRequest.ts @@ -73,7 +73,8 @@ // export default useRequest; import { RequestOptions } from '@bytedance/mona'; -import { useRequest as useAhooksRequest } from 'ahooks'; +import useAhooksRequest from 'ahooks/lib/useRequest/src/useRequest'; + import type { Options, Service } from 'ahooks/lib/useRequest/src/types'; import { request } from '..'; diff --git a/packages/mona-clients/mona-client-web/src/index.ts b/packages/mona-clients/mona-client-web/src/index.ts index 154edf800..65c0cc537 100644 --- a/packages/mona-clients/mona-client-web/src/index.ts +++ b/packages/mona-clients/mona-client-web/src/index.ts @@ -11,3 +11,4 @@ export { createPageLifecycle } from './createWebPage'; export { usePageEvent, useAppEvent, AppLifecycle, PageLifecycle } from '@bytedance/mona'; export { useMiniEffect } from './miniEffect'; +export { lazy } from './lazy'; diff --git a/packages/mona-clients/mona-client-web/src/lazy.tsx b/packages/mona-clients/mona-client-web/src/lazy.tsx new file mode 100644 index 000000000..3315c0417 --- /dev/null +++ b/packages/mona-clients/mona-client-web/src/lazy.tsx @@ -0,0 +1,53 @@ +import React, { Suspense } from 'react'; + +const wrapperStyle: React.CSSProperties = { + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + inset: 0, + zIndex: 1, + backgroundColor: 'rgb(255, 255, 255)', +}; + +const centerStyle: React.CSSProperties = { + color: 'rgba(0, 0, 0, 0.55)', + textAlign: 'center', + whiteSpace: 'nowrap', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column', + height: '100%', + width: '100%', +}; +const imgStyle: React.CSSProperties = { + width: '64%', + // margin-bottom: 5.333%; + display: 'inline-block', +}; +export const Loading: React.FC = () => { + return ( +
+
+ e.target && (e.target.src = '')} + /> +
loading...
+
+
+ ); +}; + +export function lazy(factory: () => Promise<{ default: React.ComponentType }>) { + const Component = React.lazy(factory); + return (props: T) => ( + }> + + + ); +} diff --git a/packages/mona-max/package.json b/packages/mona-max/package.json index 79952636f..f781407bd 100644 --- a/packages/mona-max/package.json +++ b/packages/mona-max/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-max", - "version": "0.2.32", + "version": "0.2.33", "description": "Cli for isv", "main": "index.js", "scripts": { diff --git a/packages/mona-plugin-events/package.json b/packages/mona-plugin-events/package.json index adfc53dd9..3d0d56cdb 100644 --- a/packages/mona-plugin-events/package.json +++ b/packages/mona-plugin-events/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-plugin-events", - "version": "0.2.32", + "version": "0.2.33", "description": "Merchant application plugin side communication package", "author": "fengbo.lucky@bytedance.com", "scripts": { diff --git a/packages/mona-runtime/package.json b/packages/mona-runtime/package.json index 8fb2b5e76..fd839690b 100644 --- a/packages/mona-runtime/package.json +++ b/packages/mona-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-runtime", - "version": "0.2.32", + "version": "0.2.33", "description": "Merchant app's developing and building tools", "main": "./dist/index", "scripts": { @@ -25,12 +25,12 @@ "typescript-transform-paths": "^2.2.4" }, "dependencies": { - "@bytedance/mona": "0.2.32", - "@bytedance/mona-client-mini": "0.2.32", - "@bytedance/mona-client-plugin": "0.2.32", - "@bytedance/mona-client-web": "0.2.32", - "@bytedance/mona-plugin-events": "0.2.32", - "@bytedance/mona-shared": "0.2.32" + "@bytedance/mona": "0.2.33", + "@bytedance/mona-client-mini": "0.2.33", + "@bytedance/mona-client-plugin": "0.2.33", + "@bytedance/mona-client-web": "0.2.33", + "@bytedance/mona-plugin-events": "0.2.33", + "@bytedance/mona-shared": "0.2.33" }, "publishConfig": { "access": "public", diff --git a/packages/mona-service/package.json b/packages/mona-service/package.json index 75e835825..e2e0d8c83 100644 --- a/packages/mona-service/package.json +++ b/packages/mona-service/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona-service", - "version": "0.2.32", + "version": "0.2.33", "displayName": "mona", "description": "Merchant app's developing and building tools", "main": "./dist/index.js", @@ -31,10 +31,10 @@ "@babel/preset-typescript": "^7.16.5", "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0", - "@bytedance/mona": "0.2.32", - "@bytedance/mona-max": "0.2.32", - "@bytedance/mona-runtime": "0.2.32", - "@bytedance/mona-shared": "0.2.32", + "@bytedance/mona": "0.2.33", + "@bytedance/mona-max": "0.2.33", + "@bytedance/mona-runtime": "0.2.33", + "@bytedance/mona-shared": "0.2.33", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.1", "@svgr/webpack": "^5.5.0", "@teamsupercell/typings-for-css-modules-loader": "^2.5.1", diff --git a/packages/mona-service/src/TargetContext.ts b/packages/mona-service/src/TargetContext.ts index 1b478a1e4..bde71829e 100644 --- a/packages/mona-service/src/TargetContext.ts +++ b/packages/mona-service/src/TargetContext.ts @@ -64,7 +64,7 @@ class TargetContext { } private _defaultStartFn(args: Record) { - const { builder } = this; + const { builder, target } = this; const webpackConfig = builder.resolveWebpackConfig(); if (!webpackConfig) { return; @@ -108,7 +108,9 @@ class TargetContext { const devServer = new WebpackDevServer(devServerConfig, compiler); devServer.startCallback(() => { - console.log(chalk.green(`服务启动成功: http://${DEFAULT_HOST}:${port}`)); + if (target !== 'max') { + console.log(chalk.green(`服务启动成功: http://${DEFAULT_HOST}:${port}`)); + } }); } } diff --git a/packages/mona-service/src/commands/common.ts b/packages/mona-service/src/commands/common.ts index ebc1dba6c..d4c1ee322 100644 --- a/packages/mona-service/src/commands/common.ts +++ b/packages/mona-service/src/commands/common.ts @@ -75,10 +75,11 @@ function isString(value: string | FileType): value is string { return typeof value === 'string'; } -export async function createUploadForm(params: Record) { +export async function createUploadForm(params: Record, argsHeaders: Record) { const form = new FormData(); Object.keys(params).forEach(key => { const value = params[key]; + if (isString(value)) { form.append(key, value); } else { @@ -104,6 +105,7 @@ export async function createUploadForm(params: Record const requestOptions: AxiosRequestConfig = { responseType: 'json', headers: { + ...argsHeaders, 'Content-Type': headers['content-type'], 'Content-Length': length, }, diff --git a/packages/mona-service/src/commands/preview/index.ts b/packages/mona-service/src/commands/preview/index.ts index 2cbb29e1d..287c75c37 100644 --- a/packages/mona-service/src/commands/preview/index.ts +++ b/packages/mona-service/src/commands/preview/index.ts @@ -10,6 +10,9 @@ import { getPlatform, getUrl, openUrlWithBrowser, + buildProject, + generateH5Qrcode, + processProjectData, } from './utils'; import { generateRequestFromOpen, requestBeforeCheck } from '../common'; import chalk from 'chalk'; @@ -35,11 +38,10 @@ const preview: IPlugin = ctx => { // assert const { user } = await requestBeforeCheck(ctx, args); - const request = generateRequestFromOpen(args, user.cookie); // common steps for all target: compress => upload - const maxProcess = [createTestVersionFactory(request), generateQrcodeFactory(request), printQrcode]; + const maxProcess = [createTestVersionFactory(request, args), generateQrcodeFactory(request), printQrcode('抖音')]; switch (args.target) { case 'max': @@ -51,6 +53,15 @@ const preview: IPlugin = ctx => { case 'light': pipe(getPlatform, getUrl, openUrlWithBrowser)({ ctx, args }); break; + case 'h5': + pipe( + buildProject('h5'), + processProjectData, + createTestVersionFactory(request, args), + generateH5Qrcode(args), + printQrcode('抖店APP'), + )(ctx); + break; default: console.log(chalk.red(`${args.target}端目前暂不支持preview命令,敬请期待`)); } diff --git a/packages/mona-service/src/commands/preview/utils.ts b/packages/mona-service/src/commands/preview/utils.ts index 72d4698f5..b0a799562 100644 --- a/packages/mona-service/src/commands/preview/utils.ts +++ b/packages/mona-service/src/commands/preview/utils.ts @@ -11,6 +11,7 @@ import fs from 'fs'; import os from 'os'; import chalk from 'chalk'; import { DEFAULT_PORT } from '@/target/constants'; +import { OPEN_DOMAIN } from '@bytedance/mona-shared'; const isWin = os.platform() === 'win32'; type Request = (path: string, options?: AxiosRequestConfig) => Promise; @@ -28,16 +29,18 @@ interface CreateTestAppVersionResp { } // pipe func -export const pipe = (...funcs: Function[]) => (input?: any) => - funcs.reduce((prev, cur) => (i: any) => { - const res = prev(i); - const isPromise = typeof res?.then === 'function'; - if (isPromise) { - return res.then((r: any) => cur(r)); - } else { - return cur(res); - } - })(input); +export const pipe = + (...funcs: Function[]) => + (input?: any) => + funcs.reduce((prev, cur) => (i: any) => { + const res = prev(i); + const isPromise = typeof res?.then === 'function'; + if (isPromise) { + return res.then((r: any) => cur(r)); + } else { + return cur(res); + } + })(input); // watch dir export function watch(dir: string, options: { open: boolean }, callback: Function) { @@ -60,18 +63,19 @@ export function watch(dir: string, options: { open: boolean }, callback: Functio } } -export const createTestVersionFactory = (request: Request) => async ( - params: Record, -) => { - const { form, requestOptions } = await createUploadForm(params); - const res = await request('/captain/app/version/test/create', { - method: 'POST', - data: form, - ...requestOptions, - }); - - return { appId: params.appId, version: res.version }; -}; +export const createTestVersionFactory = + (request: Request, args: Record) => + async (params: Record) => { + const argsHeaders = args.header ? JSON.parse(args.header) : {}; + const { form, requestOptions } = await createUploadForm(params, argsHeaders); + const res = await request('/captain/app/version/test/create', { + method: 'POST', + data: form, + ...requestOptions, + }); + + return { appId: params.appId, version: res.version }; + }; function formatNumberToTwoDigit(number: number) { return `0${number}`.slice(-2); @@ -89,38 +93,40 @@ export function getFormatedExpireTime(seconds: number) { return `${year}/${month}/${day} ${hour}:${minute}:${second}`; } -export function printQrcode(params: { qrcode: string; expireTime: number }) { - console.log(params.qrcode); - console.log(chalk.yellow(`二维码 ${getFormatedExpireTime(params.expireTime)} 到期,请尽快使用抖音进行扫码预览!`)); +export function printQrcode(appName: string = '抖音') { + return (params: { qrcode: string; expireTime: number }) => { + console.log(params.qrcode); + console.log( + chalk.yellow(`二维码 ${getFormatedExpireTime(params.expireTime)} 到期,请尽快使用${appName}进行扫码预览!`), + ); + }; } -export const generateQrcodeFactory = (request: Request) => async (params: { - appId: string; - version: string; -}) => { - const res = await request('/captain/app/version/getDynamicTestUrl', { - method: 'GET', - params: { - ...params, - previewScene: 2, - }, - }); - - const preViewCodeUrl = `aweme://goods/store?sec_shop_id=${res?.secShopId}&token=${res?.token}&tmp_id=${res?.tmpId}&enter_from=scan&entrance_location=scan&pass_through_api=%7B%22isJump%22%3A1%7D`; - const qrcode = await new Promise((resolve, reject) => { - // @ts-ignore - // qrcode render failed in windows terminal when options with small: true - QRCode.toString(preViewCodeUrl, { type: 'terminal', small: !isWin }, (err, url) => { - if (err) { - reject(err); - } else { - resolve(url); - } +export const generateQrcodeFactory = + (request: Request) => async (params: { appId: string; version: string }) => { + const res = await request('/captain/app/version/getDynamicTestUrl', { + method: 'GET', + params: { + ...params, + previewScene: 2, + }, }); - }); - return { qrcode, expireTime: res.expireTime }; -}; + const preViewCodeUrl = `aweme://goods/store?sec_shop_id=${res?.secShopId}&token=${res?.token}&tmp_id=${res?.tmpId}&enter_from=scan&entrance_location=scan&pass_through_api=%7B%22isJump%22%3A1%7D`; + const qrcode = await new Promise((resolve, reject) => { + // @ts-ignore + // qrcode render failed in windows terminal when options with small: true + QRCode.toString(preViewCodeUrl, { type: 'terminal', small: !isWin }, (err, url) => { + if (err) { + reject(err); + } else { + resolve(url); + } + }); + }); + + return { qrcode, expireTime: res.expireTime }; + }; export function buildMaxComponent(ctx: PluginContext) { console.log('build'); @@ -130,7 +136,7 @@ export function buildMaxComponent(ctx: PluginContext) { // process max component data export async function processMaxComponentData(ctx: PluginContext) { - const helper = ctx.configHelper; + const helper = ctx.configHelper || ctx.builder?.configHelper; const { appId = '', output } = helper.projectConfig; // compress @@ -194,6 +200,55 @@ export function getUrl(params: { ctx: PluginContext; platform: string; platformU return `${url}${query}`; } +export function buildProject(_target: string) { + return (ctx: PluginContext) => { + console.log('build'); + execSync(`yarn build`, {}); + + // execSync(`mona-service build -t ${target ?? 'h5'} `, {}); + return ctx; + }; +} + +export const generateH5Qrcode = (args: any) => { + return async (params: { appId: string; version: string }) => { + const domain = args.domain || OPEN_DOMAIN; + + const preViewCodeUrl = `https://${domain}/ecom-app/h5?appId=${params?.appId}&version=${params?.version}&isPreview=true&hide_nav_bar=1`; + const qrcode = await new Promise((resolve, reject) => { + console.log(preViewCodeUrl); + // @ts-ignore + // qrcode render failed in windows terminal when options with small: true + QRCode.toString(preViewCodeUrl, { type: 'terminal', small: !isWin }, (err, url) => { + if (err) { + reject(err); + } else { + resolve(url); + } + }); + }); + + return { qrcode, expireTime: Date.now() / 1000 + 8 * 60 * 60 }; + }; +}; + +// process max component data +export async function processProjectData(ctx: PluginContext) { + const helper = ctx?.configHelper || ctx.builder?.configHelper; + + const { appId = '', output } = helper.projectConfig; + + // compress + const filePath = await compressDistDir(output); + + return { + appId, + testFile: { + filePath, + }, + }; +} + export function openUrlWithBrowser(url: string) { console.log(chalk.cyan(`打开 ${url}`)); open(url); diff --git a/packages/mona-service/src/commands/publish/utils.ts b/packages/mona-service/src/commands/publish/utils.ts index 0dd8ba0b6..7a315066e 100644 --- a/packages/mona-service/src/commands/publish/utils.ts +++ b/packages/mona-service/src/commands/publish/utils.ts @@ -8,23 +8,26 @@ export async function upload(output: string, userId: string, args: any) { const header = args.header ? JSON.parse(args.header) : OPEN_DEV_HEADERS; const fileName = path.basename(output); const isOnline = domain.indexOf('jinritemai.com') !== -1; - - const { form, requestOptions } = await createUploadForm({ - 'app_id': isOnline ? '8' : '65', - 'channel_key': 'open', - 'ftype': '2', - 'uid': userId, - 'file': { - filePath: output, - fileName - } - }) + + const { form, requestOptions } = await createUploadForm( + { + app_id: isOnline ? '8' : '65', + channel_key: 'open', + ftype: '2', + uid: userId, + file: { + filePath: output, + fileName, + }, + }, + args || {}, + ); const res = await axios.post(`https://${domain}/pssresource/external-large/upload`, form, { ...requestOptions, headers: { ...requestOptions.headers, - ...header + ...header, }, }); diff --git a/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/PluginEntryModule.ts b/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/PluginEntryModule.ts index 5156fad56..f3fe01ceb 100644 --- a/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/PluginEntryModule.ts +++ b/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/PluginEntryModule.ts @@ -4,7 +4,7 @@ import { readConfig } from '@bytedance/mona-shared'; import { PageConfig } from '@bytedance/mona'; import ConfigHelper from '@/ConfigHelper'; -export const MONA_PUBLIC_PATH = '__mona_public_path__' +export const MONA_PUBLIC_PATH = '__mona_public_path__'; class PluginEntryModule { configHelper: ConfigHelper; @@ -28,13 +28,12 @@ class PluginEntryModule { const { entryPath } = this.configHelper; const module: Record = {}; - const publicPathVirtualPath = path.join(entryPath, '..', 'public-path.js') - module[publicPathVirtualPath] = `__webpack_public_path__ = window.${MONA_PUBLIC_PATH} || '/';` - const virtualPath = path.join(entryPath, '..', 'app.entry.js') + const publicPathVirtualPath = path.join(entryPath, '..', 'public-path.js'); + module[publicPathVirtualPath] = `__webpack_public_path__ = window.${MONA_PUBLIC_PATH} || '/';`; + const virtualPath = path.join(entryPath, '..', 'app.entry.js'); module[virtualPath] = this._generatePluginEntryCode(entryPath); this.name = virtualPath; - return new VirtualModulesPlugin(module); } @@ -58,7 +57,12 @@ class PluginEntryModule { const pages = Array.from(new Set((this.configHelper.appConfig.pages || []) as string[])); let routesCode = pages.map((page, index) => `import Page${index} from './${page}';`).join(''); routesCode += `const routes = [${pages - .map((page, index) => `{ path: '${page}', component: createPluginPageLifecycle(Page${index}), title: '${this.getPageTitle(page)}' }`) + .map( + (page, index) => + `{ path: '${page}', component: createPluginPageLifecycle(Page${index}), title: '${this.getPageTitle( + page, + )}' }`, + ) .join(',')}];`; return routesCode; } diff --git a/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/WebEntryModule.ts b/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/WebEntryModule.ts index 83f7d7a1a..4173eccc8 100644 --- a/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/WebEntryModule.ts +++ b/packages/mona-service/src/plugins/webpack/ConfigHMRPlugin/WebEntryModule.ts @@ -3,6 +3,7 @@ import VirtualModulesPlugin from '../VirtualModulesPlugin'; import { formatAppConfig, readConfig } from '@bytedance/mona-shared'; import { PageConfig } from '@bytedance/mona'; import ConfigHelper from '@/ConfigHelper'; +const MONA_PUBLIC_PATH = '__mona_public_path__'; class WebEntryModule { configHelper: ConfigHelper; @@ -26,6 +27,8 @@ class WebEntryModule { const { entryPath } = this.configHelper; const module: Record = {}; + const publicPathVirtualPath = path.join(entryPath, '..', 'public-path.js'); + module[publicPathVirtualPath] = `__webpack_public_path__ = window.${MONA_PUBLIC_PATH} || '/';`; const virtualPath = path.join(entryPath, '..', 'app.entry.js'); module[virtualPath] = this._generateWebAppEntryCode(entryPath); this.name = virtualPath; @@ -51,13 +54,29 @@ class WebEntryModule { private _generateRoutesCode() { const pages = Array.from(new Set((this.configHelper.appConfig.pages || []) as string[])); - let routesCode = pages.map((page, index) => `import Page${index} from './${page}';`).join(''); - routesCode += `const routes = [${pages - .map( - (page, index) => - `{ path: '${page}', component: createPageLifecycle(Page${index}), title: '${this.getPageTitle(page)}' }`, - ) - .join(',')}];`; + const HomePage = pages[0]; + let routesCode; + if (HomePage) { + routesCode = `import HomePage from './${HomePage}'; + `; + } + + routesCode += `const routes = [ + ${ + HomePage + ? ` { path: '${HomePage}', component: createPageLifecycle(HomePage), title: '${this.getPageTitle( + HomePage, + )}' },` + : '' + } + ${pages + .slice(1) + .map(page => { + return `{ path: '${page}', component: createPageLifecycle(lazy(() => import(/* webpackChunkName: "${page}" */ './${page}'))), title: '${this.getPageTitle( + page, + )}' }`; + }) + .join(',')}];`; return routesCode; } @@ -79,7 +98,8 @@ class WebEntryModule { private _generateWebAppEntryCode(filename: string) { const code = ` - import { createWebApp, show, createAppLifeCycle, createPageLifecycle } from '@bytedance/mona-runtime'; + import './public-path'; + import { createWebApp, show, createAppLifeCycle, createPageLifecycle, lazy } from '@bytedance/mona-runtime'; import App from './${path.basename(filename)}'; ${this._generateRoutesCode()} ${this._generateTabBarCode()} diff --git a/packages/mona-service/src/target/constants.ts b/packages/mona-service/src/target/constants.ts index 8211bc30d..9ea10ba0f 100644 --- a/packages/mona-service/src/target/constants.ts +++ b/packages/mona-service/src/target/constants.ts @@ -14,9 +14,9 @@ export enum Platform { H5 = 'h5', } -export const H5Html =` +export const H5Html = ` - + @@ -30,7 +30,11 @@ export const H5Html =`
-` +`; + +export const H5ProdHtml = ` +
+`; export const genPluginHtml = (buildId: string) => { return ` diff --git a/packages/mona-service/src/target/h5/chainModuleRule.ts b/packages/mona-service/src/target/h5/chainModuleRule.ts new file mode 100644 index 000000000..7916bbb4d --- /dev/null +++ b/packages/mona-service/src/target/h5/chainModuleRule.ts @@ -0,0 +1,61 @@ +import path from 'path'; +import Config from 'webpack-chain'; + +import ConfigHelper from '@/ConfigHelper'; +import { MonaPlugins } from '@/plugins'; + +import { commonChainModuleRule } from '../utils/commonChainModuleRule'; +import createPxtransformConfig from '../utils/createPxtransformConfig'; +import { Platform } from '../constants'; + +function commonCssRule(styleRule: Config.Rule, configHelper: ConfigHelper) { + const { projectConfig } = configHelper; + + const pxtOptions = createPxtransformConfig(Platform.WEB, projectConfig); + + styleRule.use('style-loader').when( + configHelper.isDev, + r => r.loader(require.resolve('style-loader')), + r => r.loader(MonaPlugins.MiniCssExtractPlugin.loader), + ); + // styleRule.use('style-loader').loader(require.resolve('style-loader') + const { typings } = projectConfig.abilities?.css || { typings: false }; + + typings && + styleRule + .use('@teamsupercell/typings-for-css-modules-loader') + .loader(require.resolve('@teamsupercell/typings-for-css-modules-loader')); + + styleRule + .use('cssLoader') + .loader(require.resolve('css-loader')) + .options({ + importLoaders: 2, + modules: { + auto: true, + localIdentName: '[local]_[hash:base64:5]', + }, + }); + styleRule + .use('postcss-loader') + .loader(require.resolve('postcss-loader')) + .options({ + postcssOptions: { + plugins: [ + pxtOptions.enabled + ? [path.join(__dirname, '../../plugins/postcss/PostcssPxtransformer/index.js'), pxtOptions] + : null, + ].filter(p => p), + }, + }); + return styleRule; +} + +export function chainModuleRule(webpackConfig: Config, configHelper: ConfigHelper) { + commonChainModuleRule({ + webpackConfig, + configHelper, + TARGET: Platform.H5, + commonCssRule, + }); +} diff --git a/packages/mona-service/src/target/h5/chainOptimization.ts b/packages/mona-service/src/target/h5/chainOptimization.ts new file mode 100644 index 000000000..cb8beff29 --- /dev/null +++ b/packages/mona-service/src/target/h5/chainOptimization.ts @@ -0,0 +1,61 @@ +import ConfigHelper from '@/ConfigHelper'; +import Config from 'webpack-chain'; +import { MonaPlugins } from '@/plugins'; + +export function chainOptimization(webpackConfig: Config, configHelper: ConfigHelper) { + const optimization = webpackConfig.optimization; + const { TerserWebpackPlugin, CssMinimizerPlugin } = MonaPlugins; + optimization.when(!configHelper.isDev, op => + op + .minimize(true) + .minimizer('TerserWebpackPlugin') + .use( + new TerserWebpackPlugin({ + parallel: true, + extractComments: false, + terserOptions: { + compress: { + pure_funcs: ['console.log', 'console.debug'], + }, + }, + }), + ) + .end() + .minimizer('CssMinimizerPlugin') + .use(CssMinimizerPlugin) + .end() + .splitChunks({ + chunks: 'all', + minSize: 20000, + minRemainingSize: 0, + minChunks: 1, + maxAsyncRequests: 30, + maxInitialRequests: 30, + enforceSizeThreshold: 50000, + cacheGroups: { + reactBase: { + name: 'react-chunk', + test: /react/, + chunks: 'initial', + priority: 10, + }, + common: { + name: 'common', + chunks: 'initial', + priority: 2, + minChunks: 2, + }, + antd: { + test: /(antd|auxo|mona-ui)/, + priority: 3, + name: 'antd', + }, + vendors: { + test: /[\\/]node_modules[\\/]/, + name: 'vendors', + priority: -15, + }, + }, + }), + ); +} diff --git a/packages/mona-service/src/target/h5/index.ts b/packages/mona-service/src/target/h5/index.ts index 55e172a7b..6d8e831e5 100644 --- a/packages/mona-service/src/target/h5/index.ts +++ b/packages/mona-service/src/target/h5/index.ts @@ -1,8 +1,8 @@ import path from 'path'; import { H5Html, Platform } from '../constants'; -import { chainModuleRule } from '../web/chainModuleRule'; -import { chainOptimization } from '../utils/chainOptimization'; +import { chainModuleRule } from './chainModuleRule'; +import { chainOptimization } from './chainOptimization'; import { chainPlugins } from '../utils/chainPlugins'; import { chainResolve } from '../utils/chainResolve'; import { IPlugin } from '../../Service'; @@ -26,8 +26,13 @@ const mobile: IPlugin = ctx => { webpackConfig.output .pathinfo(false) .path(path.join(cwd, projectConfig.output)) - .filename(isDev ? '[name].js' : '[name].[contenthash:7].js') + .chunkFilename('[id].bundle.js') .publicPath('/'); + + // if (process.env.ENTRY_TYPE === 'js' && !configHelper.isDev) { + // // webpackConfig.externals({ react: 'react', 'react-dom': 'react-dom', 'react-router-dom': 'react-router-dom' }); + // // webpackConfig.output.libraryTarget('umd'); + // } chainResolve(webpackConfig, configHelper, H5); chainModuleRule(webpackConfig, configHelper); chainPlugins(webpackConfig, configHelper, H5, H5Html); diff --git a/packages/mona-service/src/target/utils/chainPlugins.ts b/packages/mona-service/src/target/utils/chainPlugins.ts index 790e9efcb..d410e6059 100644 --- a/packages/mona-service/src/target/utils/chainPlugins.ts +++ b/packages/mona-service/src/target/utils/chainPlugins.ts @@ -46,20 +46,23 @@ export function chainPlugins( ], ]); - webpackConfig.plugin('HtmlWebpackPlugin').use( - new HtmlWebpackPlugin({ - templateContent: typeof templateContent === 'function' ? templateContent(configHelper.buildId) : templateContent, - minify: { - collapseWhitespace: true, - keepClosingSlash: true, - removeComments: false, - removeRedundantAttributes: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true, - useShortDoctype: true, - }, - }), - ); + if (process.env.ENTRY_TYPE !== 'js') { + webpackConfig.plugin('HtmlWebpackPlugin').use( + new HtmlWebpackPlugin({ + templateContent: + typeof templateContent === 'function' ? templateContent(configHelper.buildId) : templateContent, + minify: { + collapseWhitespace: true, + keepClosingSlash: true, + removeComments: false, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + useShortDoctype: true, + }, + }), + ); + } webpackConfig.plugin('DefinePlugin').use(DefinePlugin, [ { diff --git a/packages/mona-service/src/target/utils/commonChainModuleRule.ts b/packages/mona-service/src/target/utils/commonChainModuleRule.ts index bc6174756..d67f11bd5 100644 --- a/packages/mona-service/src/target/utils/commonChainModuleRule.ts +++ b/packages/mona-service/src/target/utils/commonChainModuleRule.ts @@ -38,7 +38,14 @@ function createJsRule({ webpackConfig, configHelper, TARGET }: ModuleRule) { // https://github.com/babel/babel/issues/12731 sourceType: 'unambiguous', presets: [ - [require.resolve('@babel/preset-env')], + [ + require.resolve('@babel/preset-env'), + TARGET === Platform.H5 && { + // Overall browser coverage: 94% (2021-04-06) + // https://browserslist.dev/?q=aU9TIDksIEFuZHJvaWQgNC40LCBsYXN0IDIgdmVyc2lvbnMsID4gMC4yJSwgbm90IGRlYWQ%3D + targets: 'iOS 9, Android 4.4, last 2 versions, > 0.2%, not dead', + }, + ].filter(Boolean), [require.resolve('@babel/preset-typescript')], [require.resolve('@babel/preset-react'), { runtime: 'automatic' }], ], diff --git a/packages/mona-shared/package.json b/packages/mona-shared/package.json index 8c704b714..0b14722a5 100644 --- a/packages/mona-shared/package.json +++ b/packages/mona-shared/package.json @@ -1,7 +1,7 @@ { "name": "@bytedance/mona-shared", "displayName": "mona-shared", - "version": "0.2.32", + "version": "0.2.33", "description": "mona shared utils", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/packages/mona-shared/src/search.ts b/packages/mona-shared/src/search.ts index 3b2315245..7ce89f654 100644 --- a/packages/mona-shared/src/search.ts +++ b/packages/mona-shared/src/search.ts @@ -19,5 +19,3 @@ export function stringifySearch(searchObj: Record) { }); return `?${kv.join('&')}`; } - -export const ahaha = 123; diff --git a/packages/mona/package.json b/packages/mona/package.json index 7ba840eed..6c4c3f069 100644 --- a/packages/mona/package.json +++ b/packages/mona/package.json @@ -1,6 +1,6 @@ { "name": "@bytedance/mona", - "version": "0.2.32", + "version": "0.2.33", "description": "Merchant app's developing and building tools", "main": "./dist/index", "scripts": { diff --git a/yarn.lock b/yarn.lock index 66ccc1bdf..0198280c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3186,11 +3186,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== -classnames@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== - clean-css@^5.2.2: version "5.3.0" resolved "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz"