ios 原生应用集成 react-native

前言

其实官方文档《Integration with Existing Apps》讲得挺详细,但是有点面向 ios 开发,对于 ios 开发的同学应该很容易看懂吧。不熟悉的我摸索了很久,记录一下。

重要!!!

先参考官网《Setting up the development environment》把 react-native 的开发环境搭建起来,因为基本如出一辙。对于 ios 而言, react-native 像是它的一部分子应用,本质上还是原生应用。
因为就是要用到原生的东西,所以不要用 Expo 这种方式。这个是方便开发用的,最后应该要回到原生来。

能成功启动 react-native,想必也搞定了 CocoaPods 这个麻烦的工具,用来下载原生相关依赖的。

创建 ios app

Xcode Version 14.3 (14E222b)

1、创建一个 ios app

2、填写相关信息

Product Name:顾名思义,这个应用的名字,随便填,自己记住。
Team:没有就先跳过,苹果开发要求的,上线要用到。
Organization Identifier:组织标识,公司或者产品网址倒着写,随便填。
Interface:有 SwiftUI 和 Storyboard 可选,选择 Storyboard。
Language:选 Swift 或 Objective-C 都可以。

3、操作 xcode

上图为例

先点击中间的“分屏按钮”,编辑器就会变成两个编辑区,一个打开 ViewController.m 文件,一个打开 Main 文件。虽然显示是 Main 文件,但硬盘上可以看到是叫 Main.storyboard 文件。

然后点击右边的“组件库按钮”,打开组件库,拖拽一个 button 组件到 storyboard 编辑区,也就是生成一个按钮到应用上。

最后点击左边的“运行按钮”,看到弹出来的手机模拟器上有自己加的 button 就算成功了。

Read More

react 用 vite 构建 & 用 qiankun 做微前端

工程不经常改动,就不建仓库了,弄个压缩包完事。
代码压缩包:micro-qiankun.tar.gz

背景

文章不是为了讲怎么用 react & vite & qiankun 结合搭建。搭建也不复杂,直接看示例代码就可以了。主要是这其中遇到的一个问题:

qiankun.js:17 [import-html-entry]: error occurs while executing normal script <script type=”module”>

详情如图:

记录下这个问题的产生及解决。

介绍

qiankun.js 是一个微前端框架。对于微前端,之前也尝试过《用 webpack ModuleFederationPlugin 搭建微前端》。

两者差别的话:

  1. 如果用 vite,那 webpack5 MF 肯定用不了(废话~)。
  2. 对于 qiankun,是不论框架的,基座和各个子应用可以完全不同框架,因为用的沙箱机制,可以可以云云(详看官网介绍)。
  3. 而 webpack MF 其实也不是为了微前端出来,而是共享一部分功能出来,恰好能用作微前端。最终形式是暴露出一份 js 文件给主应用引用。那就最好基座和子应用都是同框架。

个人理解:

  • 如果是成熟的几个不同项目,要揉在一起,但是彼此关联又不是很大,可以用 qiankun。
  • 如果是本身就是同一个大项目,要拆成不同模块分工维护。有很多共享的数据,可以用 webpack ModuleFederationPlugin。

Read More

记录 hexo 使用 highlight.js 实现代码高亮

一直觉得文章代码不够醒目,虽然也确实是高亮了。想着应该是这主题原因,就打算换个高亮主题,就我最喜欢的 sublime 的 monokai 主题。即使现在用 vscode 也还是用这个主题。

网上查了一下,hexo 本身就是用了 highlightjs 实现代码高亮的,但是它配置的颜色实在是不太行,要换的话,得完全自己手动。

一、关掉 hexo 本身的 highlightjs 使用

项目根目录下的 _config.yml 文件,highlight 字段 enable 改为 false。关掉原本的配置,不然会和自己手动配置冲突。

可能会遇到没生效,也就是关闭后还有高亮的效果。这时候看看 hexo 版本是不是 7 以上。我就是用了 7 版本不行,后面换了 npm i hexo@^6.3.0 就可以了。我看了下载量最多的还是 6.3.0。换了版本后可以执行下 npx hexo clean 清一下缓存。

二、下载 js 和 css

官网Download 挑选功能,然后下载。也可以现在 官网Demo 看看主题效果预览。

下载后的压缩包,把 highlight.min.js 文件放到 项目/themes/正在生效的主题/source/js 文件夹下。
把要用的主题 css 拿出来,当然也可以所有 css 文件放进去,我就放了 monokai 主题的 css 而已,其他的用不上。把 monokai-sublime.min.css 文件放到 项目/themes/正在生效的主题/source/css/highlight/styles 下。

三、引用并使用 js 和 css

项目/themes/正在生效的主题/layout/_partial/head.ejs 文件里,引入刚刚放好的 css 文件,插入代码:

<link rel="stylesheet" href="/css/highlight/styles/monokai-sublime.min.css">

项目/themes/正在生效的主题/layout/_partial/after-footer.ejs 文件里,引入刚刚放好的 js 文件,然后初始化,插入代码:

<script src="/js/highlight.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.8.0/highlightjs-line-numbers.min.js"></script>
<script>
  $(function(){
    $('pre code').each((i, el) => {
    hljs.highlightElement(el);
  });
  $('code.hljs').each(function(i, el) {
     hljs.lineNumbersBlock(el);
  });
  }());
</script>

Read More

react 基础工程 Ⅱ(@reduxjs/toolkit & @craco/craco & vite)

书接上回《react 基础工程(react-redux & react-router)》,由于最近项目上的新实践新体验,所以记录一下。

依然,代码仓库:github

一、用 @reduxjs/toolkit 创建 reducer 和 api

其实工程里已经用到这个工具,但是当时还没完全发现它的优势,还以为不过是官方推荐的比较好用的三方库而已。才知道确实简化了处理以及还有别的封装功能。

1、简化写法

以前老式的 redux 写法:

import { cloneDeep } from 'lodash';
export const addStringAction = payload => ({
  type: 'ADD_STRING',
  payload: payload,
});
export const minusStringAction = payload => ({
  type: 'MINUS_STRING',
  payload: payload,
});
const defaultState = {
  b: 'abc',
};
export default function stringReducer(state = defaultState, action) {
  const { type, payload } = action;
  state = cloneDeep(state);
  switch (type) {
    case 'ADD_STRING':
      state.b += payload;
      return state;
    case 'MINUS_STRING':
      state.b = '';
      return state;
    default:
      return state;
  }
};

用 @reduxjs/toolkit 的写法:

import { createSlice } from '@reduxjs/toolkit';
export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
  • a. 不需要再额外声明 action 了,不需要定义那些 type 了。reducers 字段下的每个方法就是个 action。用的时候直接 dispatch(increment(123)) 即可。

  • b. 而且好像可以直接改 state 上的字段,不需要返回一个完全新的 state 了?其实也是里面做了处理。看官方介绍,在注释里:

Redux Toolkit allows us to write “mutating” logic in reducers. It doesn’t actually mutate the state because it uses the Immer library, which detects changes to a “draft state” and produces a brand new immutable state based off those changes

Read More

NodeJS 的 commonjs、esm 模块使用以及一些字段释义

在之前 js 的模块化迟迟没有落地,所以 NodeJS 自己整了个 commonjs,也就是我们代码里常看到 require('moduleName')。后来浏览器支持了 esm 标准也就是代码里的 import export,NodeJS 也给加上了。

在不支持的年代,我们代码能直接写上模块化语句,都是 webpack 和 babel 的功劳。无论是 import 还是 require,最后都会处理成 _webpack_require_(应该是这个 api)。

这里记录下 NodeJS 使用 commonjs、esm 的一些注意点,以及 package.json 一些看了老是记不住的字段。

一、文件格式区分

NodeJS 要使用 esm 模块,文件必须声明为 .mjs 后缀。依然使用 .js 或者声明为 .cjs 都是使用 commonjs。

  1. 当然硬要在 .js/.cjs 文件使用 esm 语句(也就是 import)的话会报错

    SyntaxError: Cannot use import statement outside a module

  2. 反过来在 .mjs 文件使用 commonjs 语句(也就是 require)的话会报错

    ReferenceError: require is not defined in ES module scope, you can use import instead

二、混搭使用

正常使用当然是两厢安好,但是可能还是会出现一些旧模块是 commonjs 写的,新的又想用 esm 去写的情况。

  1. 在 .js/.cjs 文件引用了 esm 模块的话会报错

    require() of ES Module /xxx/yyy/zzz/utils.mjs not supported.Instead change the require of /xxx/yyy/zzz/utils.mjs to a dynamic import() which is available in all CommonJS modules.

按照指示,改成动态引入 import() 就可以了。

import('./utils.mjs').then(console.log);
// [Module: null prototype] {
//   default: [Function: runEsm],
//   runSub: [Function: runSub]
// }

可以看出,export default 导出的东西被挂载 default 字段上。上面说了在标准还没落地时,webpack 就是这么做的。不知道是不是 NodeJS 参考了这个实现。

  1. 在 .mjs 文件 文件引用了 commonjs 模块的话就没问题。= =!

只不过 commonjs 里并没有 default 这个概念,所以如 import runCommonDefault, { runExport } from './utils.cjs'; 里,runCommonDefault 就是整个 module.exports 导出的对象。而 runExport 就是纯粹对 module.exports 导出对象的解构,属于其中一个字段内容。

三、esm 模块不支持 __filename,__dirname

esm 模块里是没有 __filename__dirname 这两个全局变量的(其实不是全局变量,和 require 一样是外部传进来,姑且当其是个全局变量)。可以这样实现:

import path from 'path';
import url from 'url';
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

Read More