08月05, 2017

create-react-app自定义脚本(3)

周五发了1.1.0的版本,最大的功能是支持了多入口,当然还有其他的一些东西。

并且在之前的项目中尝试了一把,基本上能走通(就chrome41的浏览器兼容性还未测试,因为我司有一个客户端,内核还是比较老)。

暂时算可以告一段落了。下面总结一些自己的经验吧。

多入口实现

之前在网上看到有别人实现的,然而深入了一下,发现他所谓的多入口是指多个文件夹(即针对多个项目,用同一套代码,但需要开启多个端口号)。

不过他的代码对我有借鉴的作用,所以我就想到了,在根目录下配一个apps.config.js,然后提供多入口,譬如这样:

module.exports = {
    // 多入口配置
    entryList: [
        {
            name: "index",
            path: "index.js",
            templatePath: "index.html"
        },
        {
            name: "login",
            path: "login.js",
            templatePath: "login.html"
        },
        ...
    ]
}

随后只要解析这个文件即可。

hot module

讲真,我之前觉得这个没啥用。页面刷新就刷新呗,但有一种可能,譬如:

你新开一个弹窗,然后修改了弹窗的内容,如果只是devHot,它会重新刷新页面(然后需要自己手动再点弹窗)。而有了hot module,则页面会保留state状态,即弹窗还会在的,文字就修改了,这样挺舒服的。

目录说明

alt

我个人觉得这个目录设计的还是不错的。。

public用来放html页面,以及公共的js、css或者其他的(如mock数据),而src则用来放模块化的资源(js、css、image等)。

alt

可以很清楚地看到,contentBase是public目录。

在运行`yarn build时,会拷贝public里面的目录至build目录,像我改的这个项目,public下有一个data目录:

alt

是mock的json数据,在build时,我并不需要这个目录,所以我在拷贝时,选择将data目录删除:

function copyPublicFolder() {
  fs.copySync(paths.appPublic, paths.appBuild, {
    dereference: true,
    filter: function(s) {
      return !/data/.test(s);
    }
  });
}

扯一下在改造项目时碰到的一些坑

a. 变量的问题

即在html中引用了jquery地址,然后在src目录下的js中使用$会报错。

解决方式,无非以下几种:

  • 干掉eslint (并不推荐)
  • 配置eslint的globals
  • 改js文件
const $ = window.$;

所以我这边配置中也要提供外部修改eslint的方案,最终我写到了apps.config.js中。

b. 顺序的问题

譬如这样的代码:

import A from "A";
import B from "B";
const a = 1
import C from "C";

const的顺序必须写到所有的import后面去。

eslint的配置说明

alt

它只会对src目录下的js/jsx进行检查。

babel-polyfill的纠结

之前在项目中有使用这个。

但后来在和其他朋友的沟通下,他们推荐使用babel-runtime。

这两者的区别是这样的:

babel-runtime是对语法层面的解析处理,比如说async await,但它不会对API做处理。它的好处在于它不是全局的,但也带来一个问题是代码冗余。

babel-polyfill文件会比较大,大概200多K,它能够对API做出处理,比如说Array.include等。它的劣势在于影响全局。

在react-scripts中,它引入了自己的polyfill。

alt

alt

带来的问题是未来如果有了其他的语法糖,光靠这个polyfill估计难。

所以我这边最终选择了babel-runtime。当需要特别的api时,去引用core-js里面的模块即可。

翻了一个babel-polyfill的依赖:

alt

就是corejs + babel-runtime啊。。

当然,上面提到的babel-polyfill文件太大的问题也不是不能解决:

babel-preset-env 支持针对指定目标环境选择需要的 polyfill 了,只需引入 babel-polyfill,并在 babelrc 中声明 useBuiltIns,babel 会将引入的 babel-polyfill 自动替换为所需的 polyfill。

# .babelrc
{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["IE >= 9"]
      },
      "useBuiltIns": true
    }]
  ]
}

参考文章:21 分钟精通前端 Polyfill 方案

常量(DefinePlugin)说明

alt

alt

上面为什么要用JSON.stringify?

可以从这篇:webpack.DefinePlugin使用介绍 文章中找到答案。

可以看出上面的definePlugin定义了一个process.env,它的值是一个object:

{
    NODE_ENV: "",
    PUBLIC_URL: "",
    TITLE: "",
    URL_PREFIX: "" 
}

简单说一下URL_PREFIX。这个需求是这样的:

nginx不配转发,直接URL请求过去。当然这个服务器得配置允许跨域才行。

nginx的配置大概这样的:

add_header 'Access-Control-Allow-origin' 'http://www.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

由于开发环境和build环境的URL_PREFIX是不一样的。所以需要写到package.json中,写法如下:

{
    "build": "cross-env URL_PREFIX=http://www.a.com mior-react-scripts build"
}

多个环境就配置多个。。(cross-env,需要自己安装一下,yarn add cross-env -D

每次start只打开一个页面

alt

然而我试图把这个文件(openBrowser.js)拷贝到我自己的项目里面,却发现每次都是新建窗口。打印了一下错误日志:

{ Error: Command failed: osascript openChrome.applescript "http://localhost:8777"
    at checkExecSyncError (child_process.js:483:13)
    at execSync (child_process.js:523:13)
}

再尝试用react-dev-utils这个npm包,却是可以的。。有点百思不得其解。

关于cli

这两天前端又发生一件撕B大事,大漠穷秋提及angular的ng-cli特别好用。看了一下,提供的命令确实挺丰富的。

反观,create-react-app提供的脚本构建功能太少了。

譬如我想建一个action,建一个reducer,似乎不可能。当然这样的creat-react-app也变得不再纯粹了。

之前有看到rekit,功能确实挺强大的,而且创建action之类的都是可视化操作。

然而生成出来的代码,我个人觉得有些冗余,但我不否认它的这个价值,改天可以参考它的一些代码,来完成我司的一些可视化操作。

本文链接:www.my-fe.pub/post/create-react-app-custom-scripts-3.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。