# 游戏Cli构建工具magic-cli  

## Node版本  

- 统一使用最新的LTS版本，目前为`v8.12.0(LTS)`，推荐安装方式[nvm](https://github.com/creationix/nvm)  

    - 原因：Node奇数版本为stable版本，偶数版本为LTS(Long Term Support)版本，[后者维护期更长，更稳定](https://nodejs.org/en/user-survey-report/#Release-Line)  


- 统一使用`npm`作为包管理工具，不使用`yarn`  

    - 原因：npm从5.x版本以后已经加入yarn的大部分特性，包括`package-lock.json`、默认`--save`、cache重写带来的安装速度提升(不输yarn)等，[详见](https://medium.com/wemake-services/is-yarn-still-a-thing-3c6886410c83)  
    - `Node v8.x`内置了`npm v6.x`，交叉使用npm和yarn会产生功能类似的重复文件及一些未知风险，[使用比例](https://nodejs.org/en/user-survey-report/#Package-Manager-Usage)  

## 重要依赖及选择原因  

- webpack@4.20.2  

    - 目前为最新的稳定版本，相比3.x编译速度提升了近2倍，更好的代码分离机制，更多的模块类型支持，[详见](https://medium.com/webpack/webpack-4-released-today-6cdb994702d4)  
    - 使用其node api模式而非cli模式，目的在于有利于开发环境同时并存多个webpack版本，缺点是每个文件目录会比较大  
    * 疑问点，目前大部分项目应该是在3.x版本下构建，迁移成本？  

- webpack-dev-server@3.1.9  

    - 目前最新的稳定版本，适配webpack@4.x，v3.1.2之前的版本存在proxy的[bug](https://xwenliang.cn/p/5add9a8a9e10d5d73c000001)  
    
- @babel/preset-env@7.1.0  

    - 完美解决了babel-polifyll的[问题](https://xwenliang.cn/p/5a3a410b9a06a7542c000002)，无需全量打包  

- @babel/core@7.1.2  

    - 适配@babel/preset-env@7.1.0  



## 问题记录

- `magic install <template>` 原计划到`source.jd.com`上面专门开一个repo用来存放和维护今后要用到的模板，但由于访问需要登录，故放弃  
    - 替代方案：在magic-cli项目中内置template目录，用于存放模板。缺点：可拓展性差，需要发版才能更新模板，耦合性较强。  
    - 后续考虑：可否把模板放到类似github的开源平台进行维护？ 
    - 结论：在git.jd.com平台建立group作为模板仓库(magic-template)和组件仓库(vue-components/zepto-components),通过gitlab api来抽取模板和组件  
    - 缺点：需要把自己的private token绑定到环境变量`magic_GIT_TOKEN`，这已经是目前能想到的最小成本的方案了，后续待讨论...

- 考虑实现类似`magic upgrade`来更新组件库？  
    - 开始考虑实现类似magic-template的方式进行组件安装及更新，但维护成本较高且可能会有版本依赖问题  
    - 结论：和军哥讨论后决定使用模板集成组件的方式来维护组件库，把组件库内置到模版中指定的目录，通过`magic install`命令来重新安装组件库  

- 考虑替代通过检测`process.env`的方式来区分域名及环境，原因[reading-environment-variables-is-slow-operation](https://stackoverflow.com/questions/7460552/reading-environment-variables-is-slow-operation)  
    - 结论：magic模板中magic-config新增字段env，然后脚手架通过DefinePlugin设置编译时变量  

- 抽离公共css的过程中发现了问题：`optimization.splitChunks.cacheGroups.{cacheGroups}.enforce: true`会产生一个空的js文件，目前还没有官方解决方案  
    - [splitChunks can create initial chunks that are empty after CSS extraction](https://github.com/webpack/webpack/issues/7300);  
    - [extract multiple css files but created a unnecessary js file](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/279);  
    - 解决方案： 将common css模块作为entry引入，然后通过webpack-fix-style-only-entries组件删除空js文件  

- 然后抽离css过程中发现新问题，在`scss`中使用`@import`引入的`common.ssss`[不会被抽离](https://github.com/webpack-contrib/sass-loader/issues/628)  
    - 解决方案：编译完成后，将所有文件中引入的`common.csss`中的内容[匹配并移除](http://git.jd.com/jdmagic/issues/issues/5)  

- html-webpack-plugin和html-loader同时使用，会使html-webpack-plugin注入html变量失效  
    - 实现基于magic-config的变量系统，在配置文件中添加env字段用来放置编译相关的变量  
    - 困难：webpack.DefinePlugin不能在html文件中定义变量  
    - 解决方案：实现webpack plugin用于替换html中指定字符  

- open-browser-webpack-plugin在windows子系统linux(Bash on Windows)中存在问题，不能打开浏览器  
    - 使用兼容性更好的[opn](https://www.npmjs.com/package/opn)代替  

# 使用文档  

## 安装magic-cli

- npm install magic-cli -g  

- 设置环境变量`magic_GIT_TOKEN=[Private token]`(为了能从`git.jd.com`获取模板和组件):  

    - 获取Private token, 登录git.jd.com -> 右上角头像-Settings -> 左侧Account -> Private token  
    - mac设置：
        - Terminal用户：打开Terminal，输入`echo 'export magic_GIT_TOKEN=[Private token]' >> ~/.bash_profile && source ~/.bash_profile`  
        - zsh用户：打开zsh，输入`echo 'export magic_GIT_TOKEN=[Private token]' >> ~/.zshrc && source ~/.zshrc`  
    - win设置，打开cmd，输入`setx magic_GIT_TOKEN [Private token] && set magic_GIT_TOKEN [Private token]`  
    - **重要：把`[Private token]`整个替换，包括两边的中括号**  

- 绑定host(为了能上传预发环境):  

    - ``  

## magic init 创建新项目  

- `magic init -h` 输出帮助提示  

- `magic init -l` 输出可用模板列表  

- `magic init <name>` 使用指定模板创建项目，是`magic init -t <name>`的缩写  

- `magic init` 不传递参数，创建项目的过程中会提示选择模板  

- 以上`<name>` 参数均可使用模板索引传入， 例如：

    `magic init -l`输出：  
    ```
    0.zepto - based on zepto, applicable for simple single page
    1.vue   - based on vue, applicable for complex project
    2.react - based on react, applicable for complex project, too
    ```
    我们可以使用`magic init 1`或者`magic init vue`来指定使用vue模板创建项目  

- 若要终止创建项目，`ctrl+c`结束进程即可  

## magic dev 本地构建项目  

## magic build 构建项目  

## magic deploy 上传预发环境  

- 非magic-cli初始化项目可通过`magic deploy -d <distname>`来上传`<distname>`目录下所有内容，不包含本身目录。  
    - 默认上传地址是上面绑定的host地址  
    - 访问路径取决于项目目录，比如目录是`<distname>/a/b/c/index.html`则访问路径是`http://minner.magic.jd.com/a/b/c/index.html`  

## magic serve 静态部署  

- `magic serve -h` 输出有关serve子命令的帮助提示

- `magic serve -v` 查看该magic-serve版本号

- 我们可以通过在serve后面加入path、port来更加精准的操作它

    `magic serve` 默认3000端口的当前子目录

    `magic serve <path>` 部署指定目录

    `magic serve <path> -p <port>` 部署指定port的指定目录

- 若要终止serve的运行，`ctrl+c`结束进程即可  

## magic install 安装模板组件magic-components  

- `magic install -l` 列出所有当前模板可用组件  

- `magic install componentNameA componentNameB` 指定组件名并安装  

- `magic install` 安装所有可用组件（会覆盖本地已有的组件）  