React移动端webview种子项目

613 阅读3分钟

  - 使用 customize-cra 在不 eject 配置的情况下自定义配置

  - postcss-px2rem css 的 px 转换 rem

  - TerserPlugin 生产环境关闭 console

  - externals 构建的时候不打包 dependencies

  - CopyWebpackPlugin 通过拷贝的方式在 html 中引入源码

  - CompressionPlugin 构建生产环境的 gzip 包

  - 在 html 中使用 nodejs fs 模块添加 loading.html

  - react-transition-group + react-router-dom 实现路由进出场动画

  - 抽取 dependencies 主要的依赖,webpack-bundle-analyzer 分析就 1kb(gzip)

github地址

  • dependencies:

 "react": "^16.10.2",
 "react-dom": "^16.10.2",

"react-router-dom": "^5.1.2"
"react-transition-group": "^4.3.0"
  • 基于create-react-app脚手架在ejetc的情况下自定义配置

customize-cra 自定义配置webpack

webpackbar 开发的时候构建进度条

webpack-bundle-analyzer 生成环境构建分析

webpack-build-notifier 构建提示插件

postcss-px2rem  px 转换 rem插件

terser-webpack-plugin 处理js插件 比如关闭生成环境console输出

compression-webpack-plugin 构建gzip压缩包 防止后端没有开启压缩

copy-webpack-plugin 拷贝代码
  • 如果做到webpack-bundle-analyzer 分析插件只有1kb方案 

  config.externals = {    ...config.externals,    react: 'React',    'react-dom': 'ReactDOM',    'react-router-dom': 'ReactRouterDOM',    'react-transition-group': 'ReactTransitionGroup'  };

将所有的依赖抽离出来不再构建,使用拷贝插件将源码拷贝至打包目录

   new CopyWebpackPlugin(      [        './node_modules/react/umd/react.production.min.js',        './node_modules/react-dom/umd/react-dom.production.min.js',        './node_modules/react-router-dom/umd/react-router-dom.min.js',        './node_modules/react-transition-group/dist/react-transition-group.min.js',        './src/assets/js/flexible.min.js'      ].map(item => ({ from: path.resolve(__dirname, item), to: './static/js' }))    ),

在index.html 页面通过环境判断

 <% if(process.env.NODE_ENV === "production"){ %>    <script src="./static/js/react.production.min.js"></script>    <script src="./static/js/react-dom.production.min.js"></script>    <script src="./static/js/react-router-dom.min.js"></script>    <script src="./static/js/react-transition-group.min.js"></script>    <script src="./static/js/flexible.min.js"></script>    <% } else {%>    <script src="./static/js/flexible.min.js" defer></script>    <% } %>

在首屏加载loading 挂载在root下 能在立即加载loading 当代码一旦加载开始渲染也就关闭了

<div id="root">      <%= require('fs').readFileSync('loading.html') %>    </div>

关闭sw

      config.plugins = config.plugins.filter(item => item.constructor.name !== 'ManifestPlugin' && item.constructor.name !== 'GenerateSW');

使用useReducer, createContext管理状态

import React, { useReducer, createContext } from 'react';const initialState = {  count: 0};const reducer = (state, action) => {  switch (action.type) {    case 'INCREMENT':      return { count: state.count + 1 };    case 'DECREMENT':      return { count: state.count - 1 };    default:      throw new Error('action 错误');  }};export const GlobalContext = createContext();export const ContextProvider = ({ children }) => (  <GlobalContext.Provider value={useReducer(reducer, initialState)}>    {children}  </GlobalContext.Provider>);

路由的出入场动画,app 中可以使用内存路由MemoryRouter

  <MemoryRouter initialEntries={config.map(item => item.path)} initialIndex={0}>    <Transition>      {config.map(item => (        <Route key={item.path} {...item} />      ))}    </Transition>  </MemoryRouter>

import React from 'react';import { TransitionGroup, CSSTransition } from 'react-transition-group';import { withRouter, Switch } from 'react-router-dom';import './style.css';const ANIMATION_MAP = {  PUSH: 'forward', // 前进  POP: 'back' //后退};const Transtion = props => (  <TransitionGroup    className={'router-wrapper'}    childFactory={child =>      React.cloneElement(child, {        classNames: ANIMATION_MAP[props.history.action]      })    }  >    <CSSTransition      key={props.location.pathname}      classNames="fade"      timeout={300}    >      <View {...props} />    </CSSTransition>  </TransitionGroup>);const View = React.memo(({ location, children }) => (  <Switch location={location}>{children}</Switch>));export default withRouter(Transtion);

利用路由中的action 使用前进后退,使用css动画

.router-wrapper {  height: 100%;  width: 100%;}/* 路由前进时的入场/离场动画 */.forward-enter {  z-index: 1;  opacity: 0.7;  transform: translateX(100%);}.forward-enter-active {  z-index: 1;  opacity: 1;  transform: translateX(0);  transition: all 350ms;}.forward-exit {  transform: translateX(0);  opacity: 1;}.forward-exit-active {  opacity: 0.7;  transform: translateX(-100%);  transition: all 350ms;}/* 路由后退时的离场动画/入场 */.back-enter {  z-index: 1;  opacity: 0.7;  transform: translateX(-100%);}.back-enter-active {  z-index: 1;  opacity: 1;  transform: translateX(0);  transition: all 350ms;}.back-exit {  transform: translateX(0);  opacity: 1;}.back-exit-active {  opacity: 0.7;  transform: translate(100%);  transition: all 350ms;}