/webpack-v4-1

dev & pro at the same directory

Primary LanguageJavaScript

SCHEMA

  • 查看 README 方式
    • vscode 打开此文件 -> F1 -> 搜索 markdown -> Markdown: 打开侧边栏预览
  • 调试 & 构建
    • 命令解释
      • dll:dev 把 React 编译成动态链接库文件,代码没压缩,用于开发调试时,提示/报错信息更友好
      • dll:pro 把 React 编译成动态链接库文件,代码已压缩,用于提交打包发布
      • start 本地开发调试,此命令已包含 dll:dev
      • start:self 本地开发调试,此命令不包含 dll:dev
      • build:self 打包构建,打包所得的文件中,代码已压缩,脚本文件名为 chunk-[id],此命令不包含 dll:*
      • build:pro 打包构建,打包所得的文件中,代码已压缩,脚本文件名为 chunk-[id],此命令已包含 dll:pro
      • * 命令中以 :self 结尾表示:该命令每次都执行对应的 dll 命令,即使 dll 文件已存在。
    • 本地调试:
      • 命令:npm startstart 比较特殊,写法上:npm start 等价于 npm run start
      • 如果 dll 文件已存在,建议使用命令 npm run start:self
    • 打包代码:
      • 用于正式打包发布(内网/预发布/外网)
      • 命令:npm run build
    • 提交注意 提交注意 提交注意
      • 普通 commit:不要提交你本地 dist 目录下的文件;
      • 构建 commit:执行了 npm run build 命令后,要发布到内网的情况,就需要连同 dist 下的所有文件一并提交。
    • SVN 提交时,根目录下的 .idea, .vscode, analysis, cache, node_modules 这些文件夹不需要提交。设置 svn ignore 方法:
      • 右键选中需要忽略的文件/夹,TortoiseSVN > Add to ignore list > 递归或者不递归;
      • 查看 ignore list:项目根目录右击空白,TortoiseSVN > Properties,即可看到。
  • 技术框架
    • webpack@4+
      • 按需加载分割点:react.lazy 进一步分割点: [common-chunk]
      • 资源路径别名设置:webpack.config.main.base > resolve.alias ,省去 '../../..' 层层翻越去查找资源
    • react@16+
      • lazy 配合 Suspense
    • react-router@4+
      • 路由即组件,分散在自定义组件中
    • react-redux
      • 数据管理框架,用其中的 connect 方法将组件的 statemethod 映射成 props
    • react-saga
      • redux 中间件,管理有副作用action
    • immutable
      • state 转成 immutable 对象,防止开发者无意识修改 state
  • 目录结构
    • 全局 Store ( src\store )
      • | - index :暴露 storereact-redux 利用在项目模块入口文件 ( src\index.jsx ) 中提供的 Provider 将其作为全局引入
      • | - actionTypes :全局 action 类型常量,瘦action胖reducer,所以 redux-saga 中不处理业务,业务逻辑放在 reducer 中处理
      • | - reducer :全局 reducer 利用 combineReducers 方法组合分散在每个组件内的 reducer
      • | - hotelSaga :全局 Redux-saga ,用于处理副作用action,本项目目前只作为异步请求处理,详见官网第一句话描述:https://redux-saga.js.org/ 简单地改变 state 就不需要用 redux-saga 处理了。redux-saga 处理的范围由文件中的 Generator 函数:hotelSaga 定义
    • 注意: 在引入 actionTypes 类型常量时,只有在 hotelSaga 全部引入,而在每个组件中的 actionCreator 只引入该组件使用到的常量
    • 一个公用文件通常会暴露许多方法(如:methods.js)或常量(如:actionTypes.js),对其引入的方式需考虑:
      • 全部引入方式:import * as objectName from 'path/module'
      • 按需引入方式:import { name } from 'path/module'
      • 按需引入的方式,打包构建时,没使用到代码的会被 webpack 自动 treeshaking 除掉
    • 每个组件中建议只包含如下文件和目录:
      • | - componentName.jsx :视情况可拆分为 容器组件UI组件,能用 纯函数 就用纯函数
      • | - componentName.less :组件的样式,如需修改第三方库的样式,添加 :global 包裹三方样式,注意,其子元素内相同类名的三方样式也会被改写。记住一点:如果有多个相同类名,元素会继承最近父元素类名的样式 书写格式如下:
        .usercont {
          min-height: 100px;
          :global(.ant-empty) {
            color: rgba(0, 0, 0, 0.45);
            :global(.ant-empty-image) {
              height: 40px;
            }
          }
        }
      • | - store :关于组件的数据
        • | - actionCreator.js :创建组件的 action
        • | - reducer.js :业务逻辑处理
      • | - [descendant's component directory] :子组件目录,如果有的话
  • npm 依赖
    • css-loader :不要升级,升级后,样式模块化 CSS Module 会报错
    • babel-plugin-import :作为 antd 按需加载的依赖包
    • @babel/plugin-syntax-dynamic-import :给 webpack 动态 import 提供支持
    • @babel/plugin-proposal-async-generator-functions :支持新语法提案 generatorasync await 混合
    • @babel/plugin-transform-runtime :给 generator 函数运行时
  • 项目要点
    • 按需加载方案:React.lazy@loadable/component 对比参见:https://www.smooth-code.com/open-source/loadable-components/docs/loadable-vs-react-lazy/ react-loadable 不再推荐使用;
    • React.lazy 目前只支持用于 export / export default 导出的组件,这样能保证 treeshaking 正常使用。对于第三方库的组件和方法,除了三方库本身的按需加载方案之外(如:antd),不建议按需加载,采用传统的 import 写法引入即可,本项目的按需加载(React.lazy)用于项目内的自定义组件;
    • Eslint 参考规则及处理方式:
    • 进入页面方式,必须登录后才能打开页面,否则重定向回登录页面。即使是粘贴输入 URL ,权限路由 AuthorizedRoute 会发送一个请求验证是否登录有效
    • 输入 URL 打开页面,路径中必须有 app 才允许进入页面,若路径中没有 app 则重定向到 /login 页面。如果路径中在 app 后面的路由路径有误,可自定义跳转页面,如:404 ,本项目没指定
    • 本项目中,mock data 只适合 GET 请求,因为 POST 被视为修改数据的请求类型,请在项目目录下的 mocks/mockConf.js 中配置,另参见配置中的注释说明。因 mock 的接口权重较高,遇同名接口时会覆盖其他接口请求,项目进展至联调阶段后请修正为真实接口
  • 测试功能点
    • 登录页 | 顶层容器 app | 拦截器 为三大顶层组件
    • 打开项目首先进入 /login 页面,登录后跳转 /app 将其重定向至 /home,每次进入(或刷新) /app/**/* 页面都会发送一个请求验证是否登录有效,若无效则重定向至 /login。进入了 /app/**/* 后切换路由达到页面变化,是不会发送请求验证登录是否有效的,登录名和密码: abc 123
    • 主要在 /home 页面做测试,页面中的按钮 Toggle backgroundChange self bkChange parent bk 测试不使用 redux-saga 处理 action 的情况,改变 /home 及其子组件 someone 各自的背景颜色和测试子组件改变父组件的背景颜色(组件间相互通信)
    • /home 页面的按钮 Get a random 获取一个随机数
      • 测试 redux-saga 处理 Side Effectsaction 情况
      • 测试根据返回结果中的状态码为 3 时,拦截器拦截每次请求的 response 会触发拦截器组件 ResponseInterc 以重定向至登录页/login
    • 样式模块化 参见 ProductB.jsx AntdTest.jsx 组件及其关联的 less 样式文件

ISSUES

1. react-router 4.x,正常写法时报 warnings,如下:

<Route path="/" exact component="{Home}" />
<Route path="/product" component="{Product}" />
<Route path="/about" component="{About}" />
<Route path="/login" component="{Login}" />
Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`.
  in Route (created by App)
  in App
  in Router (created by BrowserRouter)
  in BrowserRouter
  • Solution
    • 解决办法参见 github issue:remix-run/react-router#6420
    • component 可以换成 render 两者的区别:
      • component 会强制刷新其下的子组件,不管子组件的 shouldComponentUpdate 是否 return false
      • render 表现正常,刷不刷新子组件由 shouldComponentUpdate 返回结果决定,建议使用 render
    • 将其写成如下格式,即可 fix warning,如下:
      <Route path="/" exact component={props => <Home {...props} />} />
      <Route path="/product" component={props => <Product {...props} />} />
      <Route path="/about" component={props => <About {...props} />} />
      <Route path="/login" component={props => <Login {...props} />} />

2. react-router 4.x 刷新内嵌路由的页面报错,而刷新顶级路由没问题