hufeng / react-code-ai

crazy idea fo fronted end
MIT License
4 stars 1 forks source link

babel code AI 🚀🚀 #1

Open hufeng opened 5 years ago

hufeng commented 5 years ago

Compiler is your framework.

前端进入的compiler的时代,有了这层compiler会让整个前端进入工程化的时代。 过去我们要在framework层做的事情,现在更多的可以考虑在compiler做创新。 因此我们不断地去探索,是不是可以通过compiler让我们在构建前端应用的时候变得更加的简单。

hufeng commented 5 years ago

idea-1 自动导入react

可以通过分析代码中是不是有jsx的语法,以此来自动的导入react的依赖,懒才是生产力

import React from 'react';

P.S 不过这个问题会变的比较有意思,在useState,useEffect等的hook上来之后,这些都需要从react导入

import {useState, useEffect} from 'react'

最后是不是当有hook的时候变成这样,

import React from 'react';
import {useState, useEffect} from 'react';

😃

hufeng commented 5 years ago

idea-2 自动显示ui布局 显示每个元素的虚拟边框

在写前端布局的时候,经常需要知道element的边界位置,便于我们定位解决样式的问题 常常在写rn的view的时候就是不断地给样式加入backgroundColor: 'xx', 然后再删除 这样做效率比较低,而且不够全面,往往问题是系统性的 需要周围的元素共同参与定位 这个有点eggache,不断地该代码,解决问题了再删除代码。

在思考是不是这个诉求我们做进入babel的plugin中,简单的设计一下

1. 假设我们的源码,

function Hello() {
  return (
    <View>
        <Text>hello</Text>
    </View>
  )
}

2. babel plugin


export default function(babel) {
  const { types: t } = babel;

  return {
    visitor: {
      JSXOpeningElement(path) {
        const {node} = path;
        node.attributes.push(t.jSXAttribute(
          t.jSXIdentifier('style'),
          t.jSXExpressionContainer(t.objectExpression([
            t.objectProperty(t.stringLiteral('borderWidth'), t.numericLiteral(1))
          ]))
        ))

      }
    }
  };
}

3. output

function Hello() {
  return (
    <View style={{ "borderWidth": 1 }}>
        <Text style={{ "borderWidth": 1 }}>hello</Text>
    </View>);

}

^_^😃,Cool?

但是如果这样开启就等于所有的jsx的元素都会被添加,我们实际的场景可能更需要再当前的开发页面, 我们可以添加一个开启开关,类似pragma

/**
 * @showborder
  */ 

还有什么好玩的,可以学习地图的染色原理,用几种颜色才能涂满这个screen?

packages/babel-plugin-rn-jsx-border-grid 支持相对路径的递归

hufeng commented 5 years ago

idea-3 怎么优雅管理配置?

每个项目都需要去管理各种配置项,以此来应对外界的变化,比如开发环境等。

后端都比较有完善的配置管理,前端也需要规范起来。

不好的实践,是配置项到处游走,这边配置几个,那边配置几个,然后满带代码的if/else的判断, 切测试环境需要改代码,提交代码又改参数配置,发布需要改,像一个没头苍蝇到处改,大大增加了 我们开发过程中的心智负担。

怎么去简化这个问题呢?

  1. 中心化配置
  2. 根据环境不同来区分配置参数(这样切换不同的环境只需要改环境变量的配置就可以了,Go语言了解下😃)
  3. zero runtime cost(Ru什么t,什么ust)

开始设计

配置只允许在一个位置,同一个概念是和谐一致的。 --config --index.js -- module entry --dev.js --test.js --prod.js

然过ts给与类型信息,让代码更好的感知语义。

好的,问题来了index.js中的代码大概就是

let env;

if (process.env.NODE_ENV === 'development') {
  env = require('./dev').default;
} else if (process.env.NODE_ENV === 'test') {
  env = require('./test').default;
} else if (process.env.NODE_ENV === 'production') {
  env = require('./prod').default;
}

export default env;

然后通过"babel-plugin-transform-node-env-inline": "^0.4.3" 根据环境变量动态的替换process.env.NODE_ENV

{
  "devDependencies": {
    "babel-plugin-transform-node-env-inline": "^0.4.3"
  },
  "scripts": {
    "prod": "NODE_ENV=production babel src/index.js --out-file output/index.prod.js",
    "test": "NODE_ENV=test babel src/index.js --out-file output/index.test.js",
    "dev": "NODE_ENV=development babel src/index.js --out-file output/index.dev.js"
  }
}

就可以到达我们的目标,但是我们看看编译后的代码

let env;

if (!'production' || false) {
  env = require('./dev').default;
} else if (false) {
  env = require('./test').default;
} else if (true) {
  env = require('./prod').default;
}

export default env;

这么有大量的ifelse和模块的引入,对于bundler来说是不回去判断ifelse的会把dev,test,prod.js全部引入 进来,造成不必要的代码体积.

这个时候我们需要另外一个神器, "babel-plugin-minify-dead-code-elimination": "^0.5.0",

{
  "devDependencies": {
    "babel-plugin-minify-dead-code-elimination": "^0.5.0",
    "babel-plugin-transform-node-env-inline": "^0.4.3"
  },
  "scripts": {
    "prod": "NODE_ENV=production babel src/index.js --out-file output/index.prod.js",
    "test": "NODE_ENV=test babel src/index.js --out-file output/index.test.js",
    "dev": "NODE_ENV=development babel src/index.js --out-file output/index.dev.js"
  }
}

//.babelrc

{
  "plugins": ["minify-dead-code-elimination", "transform-node-env-inline"]
}

来智能删除我们的dead code

let env = require('./prod').default;

export default env;

amazing!!!👏👏

demo

hufeng commented 5 years ago

idea-4 自动抽取react-native中的inline style

在我们开发react-native的过程中,常常都是先写内联样式,然后再做样式的抽取

function Hello() {
  return (
     <View style={{flex:1, backgroundColor: '#FFF', alignItems: 'center', jusityContent: 'center'}}>
        <Text style={{color:'#EEE'}}>hello world</Text>
     </View>
   )
}

随着UI的component的tree越来越大,就不想再去抽取,很多这样的样式就存在于我们的代码之中, 这样有什么不好,代码的可读性要差一点,一些展示逻辑淹没在这些样式对象之中,另外一个就是写性能不是很好,影响的是序列化。标准的react-native中使用StyleSheet.create创建的对象样式。

面对这样的代码,怎么方便的管理呢。

基于babel分析jsx的jsxAttributesde属性对象中的style, 然后抽取到const styles = StyleSheet.create({})之中,key的名字可以根据样式对象来md5,保证唯一性。