07月27, 2017

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

上一篇地址:create-react-app自定义脚本

中间隔了三个月,create-react-app的代码也是变化蛮大的,比如新增了serviceWorker,webpack升级到2了,代码风格更加优雅之类的,很多var变成了const(我无聊用sourceTree对比了一下)。

由于KPI的关系,不得不把这东西整一个版本出来。当然在整的过程中,我也收获了很多。

npm owner && npm pack

这里简单扯一下npm owner

对于公司而言,理应有一个npm账户,然后里面有多个项目,将这些项目的owner权限下发下去。当某个员工离职后,将该员工的owner权限剔除。

alt

当然在npm owner add或者rm的时候,请确保是npm源,而非taobao源,不然会报错。

噢对,这里还有一个命令:

npm whoami

快速查看当前的npm登录者是谁。

npm pack是会生成一个taz压缩包,截图如下:

alt

为什么要有这个?在下文中会有解释。

lerna

这是我之前没有注意到的,creat-react-app很早就用了lerna

打开上面的官网,就能看到这句话:

A tool for managing JavaScript projects with multiple packages.

alt

react-scripts这个npm包的路径应该是在这儿,而不是github的react-scripts

本地包测试

说个愚蠢的事,我昨天改了大概了10多次bug,发布了10多次。

其实我大概知道怎么改,就像我之前写node工具一样的改法嘛(挺自以为是的。。),但我就是懒啊。

考虑到同事要跟我一起来改这个代码,所以我不能让同事像个SB似的,改一次发一次,才能看到最终效果。

于是早上过来之后,在我的custom-react-scripts项目下,执行npm link。随后,再尝试,发现并不行,会报以下错误:

Aborting installation.
yarnpkg add --exact react react-dom custom-react-scripts has failed.

于是我蒙B了。然后顺着这个思路,npm link可以用来做软链接,譬如:

# A文件夹
npm link
# B文件夹
npm link ‘A文件夹的npm名称’

这样一来,B文件夹里面的node_modules就有了A文件夹。那么这个思路是否可行呢?

简单描述一下测试方法:首先先全局卸载create-react-app,然后github上clone create-react-app这个项目,进入它packages目录里面的create-react-app,做一个软链接,全局就有了create-react-app,再就是改create-react-app代码即可。

alt

我将dependencies的第三个参数拦截下来,用yarn link npm包名的方式来处理。

但最后发现不行,不行的原因是link不会去安装依赖模块,即我上面的A文件夹package.json里面有一些依赖。

幸运的是,有一个技术群的群友发了我一个链接:Make CRA can install local custom react-scripts package which is work in process

方案就是我上面提的用taz文件,所以我只要把本地文件夹打个taz,然后用绝对路径即可。

create-react-app 文件名 --scripts-version /Users/zhangpu/custom-react-scripts/mior-react-scripts-0.1.17.tgz

基于react-scripts改的新功能

  • 将默认端口号改为3001
  • 支持less
  • 支持装饰器(注解)
  • 在index.js中默认引入antd-css-rewrite模块。webpack配置中集成antd css动态加载
  • prod环境生成持久缓存的verdor.min.js
  • prod环境去掉sourceMap
  • 默认生成.env文件,提供三个配置:PORT(项目启动端口号)、myProxy(转发请求的URL,考虑到配置到package.json中容易冲突,每个人的请求URL可能不同)、TITLE(项目title,会改写index.html中的title),即可以在.env里面这样写:
PORT=3003
myProxy=http://localhost:6002
TITLE=测试标题
  • 默认在package.json中加入以下依赖:
{
    "dependencies": {
        "antd": "^2.7.4",
        "axios": "^0.16.1",
        "prop-types": "^15.5.10",
        "antd-css-rewrite": "^1.0.0",
        "react-router": "^3.0.2"
    }
}

默认react及react-dom是有的


挑上面一两个说说吧。

a. 在react-scripts中,它有这样的一段代码:

alt

它会读取template中的.template.dependencies.json文件,添加依赖到args里面。这里需要注意的是这个文件的写法,程序中会读取dependencies的key,所以不要忘记这个。

在往下读的时候,觉得有些好笑:

if (!isReactInstalled(appPackage) || template) {
    console.log(`Installing react and react-dom using ${command}...`);
    console.log();

    const proc = spawn.sync(command, args, { stdio: 'inherit' });
    if (proc.status !== 0) {
      console.error(`\`${command} ${args.join(' ')}\` failed`);
      return;
    }
  }

// ...
function isReactInstalled(appPackage) {
  const dependencies = appPackage.dependencies || {};

  return (
    typeof dependencies.react !== 'undefined' &&
    typeof dependencies['react-dom'] !== 'undefined'
  );
}

上面的if会导致自己写的依赖安装不了。因为creat-react-app默认先安装react/react-dom/react-scripts,然后这三者成功之后,执行react-scripts里面的init.js,所以isReactInstalled就是true。

在我自己的代码中,把上面的if判断给去掉了。

b. prod环境生成持久缓存的verdor.min.js,这个参考了饿了么的webpack 实现持久性缓存,配置如下:

// 抽离第三方文件
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function (module) {
    return module.context && module.context.indexOf('node_modules') !== -1;
  }
}),
// 提取 webpack 的 runtime 代码
new webpack.optimize.CommonsChunkPlugin({
  name: ['manifast']
}),
// 生成稳定的 hash 文件名
new webpack.HashedModuleIdsPlugin(),

c. env的TITLE变量替换实现思路:

我看index.html是这样写:

alt

本以为是HtmlWebpackPlugin这个插件的功能,但看了一下不是的,它用了另外一个插件:

alt

再跟踪进去源码:

alt

豁然开朗。随后找到相关代码,改掉即可。

prod的publicPath配置

一般比如说我们上线,希望是http://www.xxx.com,但现实可能是http://www.xxx.com/path,会有一个path,这个path即是我们的publicPath配置。

要是通过npm eject来让我们自己配置webpack,那么简单粗暴地把publicPath写死即可。

但是这样一来,并不优雅。

我们可以找到这样一段:

alt

alt

alt

顺利get,只要在package.json里面配置homepage即可。

这里的url.parse(publicUrl).pathname写的代码,我表示有些疑惑:

alt

为什么不直接publicUrl呢?

serviceWorker

在最新的react-scripts代码中,新增了serviceWorker。

我个人对它的理解是有点像H5的离线缓存。

alt

未来

其实我本人有一点点的小小心思,v2.0.0准备用我自己的目录结构(就是按我对react/redux的分层理解),不过这些要经历项目的炮火攻击,才能一点点地变成成熟起来。

后面要做的工作有很多,譬如要测试和待增加的功能:

  • 测试路由功能(分片加载)
  • 正式环境移除propTypes
  • 研究多个主入口实现

好在v1.0.0已经发布了。

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

-- EOF --

Comments

评论加载中...

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