# tua
tua是一个基于webpack的工作流，集成了下一代开发语言，提供语言层面的支持。
它封装了webpack的复杂度，并集成了webpack使用的最佳实践。
让开发者更加关注业务，而非复杂的配置和工具选择。

## 1. 快速开始
1. 通过 npm 或 yarn 安装tua
    ```shell
    npm i -g tua
    yarn add global tua
    ```
    注意，使用yarn，需要配置环境变量。否则，全局命令不生效。
2. 在项目根目录下执行初始化命令
    ```shell
    tua -i
    ````
    此命令会在项目根目录下生成 **tua** 的配置文件`.tuarc`，以及一个简单示例。并自动下载安装所需npm依赖。
    可以根据项目需要修改配置。见 `tua` 配置说明。
3. 开始调试
    ```shell
    tua -s
    ```
    启动服务器。会自动在浏览器（现在默认是chrome）中打开页面。

## 2. 命令行接口(CLI)
### 2.1. 初始化生成项目模板
```shell
tua -i
```` 
执行后会执行目录下生成简单的项目模板。
#### 2.1.1. 模板结构
```
+ src          代码源文件
  + lib        公共代码库
    utils.js   公用的js
  index.js     入口
  index.html   html模板
+ test         测试文件
  add.js     测试文件
package.json   包配置文件
.tuarc         tua配置文件
```
#### 2.1.2. 自动下载
在生成package.json后，npm包的自动安装会启动。优先使用yarn安装，如果没有安装则会选择npm。

### 2.2. 生成DLL文件
DLL是套用window中动态链接库的概念。
DLL的使用，是webpack优化的一部分。
把变化不频繁的部分（如 vue react 的库文件等）打到DLL包中，可以提升调试阶段和发布阶段的编译速度，节省时间，提升效率。
如需了解详情，请自行google，这里不再累述。

```shell
tua -d
``` 
此命令无需手动执行，在使用 `-s` 或 `-p` 时，程序会自动检测是否需要生成或更新 DLL 文件。

### 2.3. 启动本地调试服务器
```shell
tua -s
```
启动一个webpack-dev-server，带有热更新。
启动前，会检测是否需要更新 DLL 文件。

默认情况下，webpack-dev-server 提供一个 express 的服务器，在这里，额外提供对 koa 服务器的支持，只需在此命令的末尾添加 `koa`,
```shell
tua -s koa
```
以上命令会启动Koa服务器。

### 2.4. 打包
#### 2.4.1. 打包到本地
```shell
tua -p
```
打包后，资源路径都是本地相对路径，用于本地查看或html和资源部署到同一目录的情况。
打包会同时打包客户端代码和服务端代码，服务端代码入口在 `serverEntry` 配置处设置。见下文详细说明。

#### 2.4.2. 打包到服务器
```shell
tua -p toserver
```
打包后，资源路径指向 .tuarc 中配置的 `serverUrl`， 用于使用CDN或者html和资源部署到不同路径的情况。

### 2.5. 启动测试
```shell
tua -t
```
集成了 `karma + mocha + chai + sinon` 的测试框架。
需配置 .tuarc 中的 `testbase`，默认是 test 文件夹。

### 2.6. 执行js文件
```shell
tua --run {filename}
```
此文件中可以调用 tua 的模块，以及 tua 依赖的 npm 包。

## 3. 配置
tua 的配置文件 `./.tuarc` 在执行初始化命令之后自动在项目的根路径下生成。
.tuarc 是一个正规的 nodejs 模块，暂不支持ES6语法。
以下是每一个配置项的说明。

### 3.1. supportIe{Boolean} deprecated in 0.9.0
打包后的文件是否支持 IE8。默认给出的选项是`false`。
IE8 的支持需要一些特殊的库以及 webpack 插件的支持，当选项为`true`时，工作流会自动调整配置，以适应IE8的要求。
注意： IE8的支持不完全，某些 ES6 的属性慎用。另外，如需搭配 vue 等不支持 IE8 的库，请自行查询如何配置loader和插件以提供兼容。

注： 0.9.0 已经不再支持IE8。

### 3.2. cssEnhance {Array<string, object> | string | object }
css 增强loader，单个loader配置符合 webpack 标准的loader配置

#### 3.2.1. 支持的loader
* 内置css loader： sass，postcss，less
* 本地安装的 css loader 需要加上 -loader，如使用本地安装特定版本的 postcss， 可配置成 postcss-loader

#### 3.2.2. 关于 postcss
默认配置中，postcss使用的插件如下：
* postcss-smart-import
* precss
* autoprefixer

配置文件生成规则如下：
1. 自动生成 .postcssrc.js
   默认会根据浏览器环境配置 `env` 在项目根目录下生成 **.postcssrc.js**， 此文件使用 tua 包中默认安装的 postcss插件地址，因此每人机器上配置文件不同，不要上传到版本库。

2. 用户自定义配置 postcss.config.js
   用户在定义了 postcss.config.js 的情况下，上述配置文件不会自动生成，如果已经生成，请手动删除，以免造成不确定性的bug。

#### 3.2.3. 注意事项
1. 数组对象配置的顺序符合webpack loader加载对象从右向左处理的顺序

### ~~ 3.3. pretty {Boolean | Object}~~
是否在启动 webpack 时，使用[prettier](https://github.com/prettier/prettier)自动格式化代码。
如果需要格式化代码，则`pretty`的值应该是 [prettier](https://github.com/prettier/prettier) 的配置。

### 3.4. enableProfile {Boolean}
是否生成profile文件，profile可用于查看生成块的大小等信息。
如果选是，打包完成后，会自动打开集成的profile工具，可方便的查看每个 chunk 的信息。

### 3.5. env {Object}

```js
 /**
     * 定义浏览器环境，babel-preset-env 插件使用的环境
     * browsers {Array<string> | string} 浏览器支持
     *     或者 {
     *              debug: {Array<string> | string}, 浏览器支持
     *              publish: {Array<string> | string} 浏览器支持
     *          }
     * https://github.com/ai/browserslist http://browserl.ist/
     */
    browsers: {
        debug: '',
        publish: ''
    }
```

可分别定义debug阶段和发布阶段打包支持的浏览器环境。
在调试阶段把环境设置成固定的（比如 chrome） 可以加快编译速度，减少等待时间。

### 3.6. pageEntrys {Function}
配置项目的入口，重要属性，必须配置。 **路径中注意要统一使用 / , windows 中会使用 \ ，需自行处理**
值需要是一个匿名函数。
```js
 /**
 * @param params 用于过滤等功能的cli传过来的参数 两个命令可以传递此参数 tua -s ?params, 或者 tua -p toserver?param / tua -p ?params
 * @returns {Array}
 *     uri: {String} 访问路径，用于 server.mfs 获取唯一的页面模板。为了解决htmlsrc相同的问题，优先使用router作为map的key，不存在使用htmlsrc
*      htmlout: {String} 生成后的html文件的路径，相对于 {dist} 路径
*      htmlsrc: {String} 源html文件模板路径，相对于项目根路径
*      jssrc: {Array} html文件对应的js入口文件地址, 必须是数组
*      jsout: {String} html对应的js或css打包后的块名称，只是名称，所有模块打包后 script 会放到 {dist}/scripts/ 下
*                      css会放到 {dist}/styles/ 下
* }
*/
pageEntrys: function (params) {
    return [{
        uri: '',
        htmlsrc: '',
        htmlout: '',
        jssrc: [''],
        jsout: ''
    }];
}
```
参数 函数接受一个参数，可以在 `-s` 或 `-p` 阶段，用 `?xxx` 的方式传递过来，常用于优化调试速度，或部分打包上线。默认会打包所有页面。
返回值需要是一组符合上述结构的对象。

### 3.7. html {Object}
html-webpack-plugin 中关于html生成的压缩配置。见:[https://github.com/kangax/html-minifier#options-quick-reference](https://github.com/kangax/html-minifier#options-quick-reference)

### 3.8. testbase {String}
测试文件路径

### 3.9. dist {String}
打包代码输出的文件夹路径，需要是绝对路径。

### 3.10. src {String}
代码source路径，缩小loader的处理范围。

### 3.11. assertsLimit {Integer}
大小小于 {assertsLimit}B 的资源，会自动base64到代码中。

### 3.12. serverUrl {String}
执行打包到 toserver 时，静态资源会上传至cdn，此为静态资源文件夹地址。

### 3.13. open {String | Boolean | Object}
是 webpack-dev-server 中 open 和 openPage 的缩写，其中

#### 3.13.1. open 设置为浏览器类型
```js
open : 'google chrome'
```

#### 3.13.2. open设置为布尔值时
```
open : false
```
值 false 时，不自动打开浏览器。
true时，打开当前服务地址

#### 3.13.3. open设置为对象时
```js
open : {
    uri: 'xxx.html',
    app: 'google chrome'
}
```

执行 `-s` 后，启动服务器成功后浏览器打开地址。

** 如果 webpack 的 `devServer` 配置和`open`配置同时存在时，以 `open` 的设置为准，`open`不存在时，以`devServer`的配置为准 **

### 3.14. devServer {Object}
```js
{
    proxy: {
        "/api": {
            target: "http://localhost:3000", //代理的服务器地址
            bypass: function (req, res, proxyOptions) {
                //过滤器
            }
        }
    },
    port: 9527
}
```
可设置proxy和端口号。

### 3.15. resolve {Object}
```js
{
    /**
     * 别名配置，可以配置短路径和文件
     * eg. "jquery" : require("./lib/jquery")
     */
    alias: {
        // "jquery" : require("./lib/jquery")
    }
}
```
可配置别名，如上例为 jquery 配置了别名。

### 3.16. globalVar {Object}
为某些模块配置全局变量。
如：
```js
{
    $: 'jquery'
}
```

### 3.17. dllchunk {Object}
配置dll块，至少配置一个，否则会出错。
如：
```js
{
    vendor: ['./src/lib/utils'],
    // vendor2: ['./lib/kEvent']
}
```

### 3.18. serverEntry
serverEntry 应该是一个 String 类型的值。

```js
serverEntry : './server/index'
```
* serverEntry 值存在时，debug阶段会自动启动后台服务，提供server对象给入口文件
* 不存在时，同以前开发纯前端输出的形式

#### 3.18.1. 入口
入口模块必须默认是一个方法，支持两种形式，es5的模式
 ```js
 module.exports=function(server){
    
}
 ``` 
 或者 es6 模式
  ```js
  export default (server)=>{
     
 }
  ``` 
  
方法需从 server 对象中获取 router 和 app 等用于创建路由和后台直出。
```js
//index.js
module.exports = function (server) {
    const router = server.router;
    const app = server.app;
    //koa example
    router.get('/bbbf', function (ctx) {
        ctx.type = 'text/html';
        let htmlcode = server.mfs('/app/index.html', 'utf-8');
        ctx.body = htmlcode + ' for koa!';
    })
//express example
    router.get('/bbbc', function (req, res, next) {
        let htmlcode = server.mfs('/app/index.html', 'utf-8');
        res.send('for express： ' + htmlcode);
    })
}
```

#### 3.18.2. 入口接收的 server 对象
debug 阶段的 `server`是`webpackDevServer`的实例，常用到的属性和方法如下
```js
{
    app: {koa or express}
    router: {koa-router Object or express router Object}
    mfs: {Function}
}
```

#### 3.18.3. mfs 方法
```js
/**
* 读取html模板的代码
* @param htmlPath 源代码中，html文件的路径
*/
function mfs(htmlPath){}
```
注意，路径需要以 '/' 开头，对应项目根目录。

#### 3.18.4. 使用打包后的服务端文件
打包后，会生成 `dist/server/index.js`, 此文件中不包含服务器创建部分，因此，使用时，需要根据入口文件中使用到的server的属性，创建相应的对象

以使用`koa`为例，boot.js,
```js
require('source-map-support').install();//支持 sourcemap
const entry = require('./dist/server/index');
const Koa = require('koa');
const Router = require('koa-router');
 // 初始化koa实例
const app =  new Koa(); // eslint-disable-line
const router = new Router();//初始化koa router

app.use(router.routes()).use(router.allowedMethods()); //绑定路由
entry({
    app: new Koa(),
    router: new KoaRouter()
})
```
其中， `source-map-support` 需要在服务端安装npm包。非必须，不需要可删除。

### 3.19. babelrc
```js
/**
 * {
 *    presets: {Array<string> | string}
 *    plugins: {Array<string> | string}
 *  }
 */
{
    presets: {Array<string> | string},
    plugins: {Array<string> | string}
}
```
用于扩展 .babelrc，例如，如果需要使用react，需要这么写：
```js
{
    presets: ["react"]
}
```

## 4. 进阶
### 4.1. 直接调用 tua 时的参数传递
**.tuarc** 配置文件中的 **pageEntry** 方法可以接收一个名为 `params` 的参数：
```js
pageEntrys: function (params) {
   //params可以用于过滤入口和html文件
   return entryDatas;
}
```
这个参数在过滤入口和页面时会显得尤为有用，它可以通过执行 `-s` 或 `-p` 后添加 `?{param}` 来添加
```shell
tua -s ?xxx
tua -p ?xxx
tua -p toserver?xxx
```
#### 4.1.1. 调用配置在 npm scripts 中命令的参数传递
**npm scripts**中可以很方便的配置命令行，可以结合其他命令，方便调用。
比如：
```js
 "scripts": {
    "toserver": "rimraf dist/* .cache-loader/* && tua -p toserver && kcms -c"
  }
```
但，使用这种方式的时候，无法给**pageEntry**方法传递参数。

为了支持 **npm scripts** 中调用**tua**命令时传递参数，需要设置 **npm** 的参数 `--params`：
```shell
npm run toserver --params=xxx
```
这时，.tuarc 中的 pageEntry 方法就会接收到 'xxx'。

#### 4.1.2. 使用 koa 作为服务器

默认在webpack-dev-sever中，使用express作为服务器，但加载koa模块会略显复杂。

`-s` 在检测到最后一个参数为 `koa` 时，会启用 `koa` 作为服务器。

```shell
tua -s koa

tua -s ?xxx koa
```
默认增加了对node端sourcemap的支持，方便定位问题。

### 4.2. 设置目标浏览器环境
#### 4.2.1. 不区分开发阶段的配置
在 .tuarc 的配置文件中， `env.browsers` 可以用来设置目标浏览器。值可以是 ` {Array<string> | string} `。
```js
env:{
browsers: {Array<string> | string}
}
```
#### 4.2.2. 区分测试和发布阶段的配置
 一般，在debug模式下，可以只支持chrome就可以完成开发。
```js
env:{
    browsers: {
         debug: {Array<string> | string},
         publish: {Array<string> | string}
    }
}
```
### 4.3. 使用工具中的模块
#### 4.3.1. 获取当前环境
```js
let env = require("@tua/utils/env");
console.log(env.DEBUG);
console.log(env.PUBLISH);
console.log(env.TOSERVER);
```
以上方式可以获取当前是处于 `DEBUG`,`PUBLISH`,`TOSERVER` 的状态，方便自助扩展webpack使用。

#### 4.3.2. 自定义启动文件
执行命令 
```shell
tua --run start.js
```
start.js
```js
let tua = require("@tua");
tua.start();
```
以上代码可以启动 `dev server`。
可用的 tua API，见下面部分。

## 5. API
### 5.1. .DLL(suc, fail)
根据 __tua.js__ 中的配置，生成 __dll__ 文件。
##### 5.1.1. suc
生成dll文件成功后的回调
##### 5.1.2. fail
生成dll失败后的回调

`suc`和`fail`都是可选参数。

### 5.2. .start(params, callback, spinner)
启动服务器
##### 5.2.1. params
参数，可用于过滤入口
##### 5.2.2. callback
启动服务器成功后的回调
##### 5.2.3. spinner
webpack的devserver启动中，需要此对象展示阶段性信息，不传默认不展示。

三个参数都是可选。

### 5.3. .pack(stat, params, suc, fail)
打包发布项目
##### 5.3.1. stat
PUBLISH TOSERVER 两种选一，不传默认是PUBLISH
##### 5.3.2. params
参数，可用于过滤入口
##### 5.3.3. suc
成功回调
##### 5.3.4. fail
失败后的回调

四个参数都是可选。

## CHANGELOG
### 2018-03-27 v0.8.26
* 支持异步加载块 import()

### 2018-03-26 v0.8.25
* uglify 压缩打包默认输出 sourcemap

### 2018-03-15 v0.8.23
* 增加测试阶段服务端（node）sourcemap 支持
* 增加服务端线上环境 sourcemap 支持

### 2017-11-20 v0.8.19
* 开发模式兼容 windows
* loader配置路径兼容 windows /转为\

### 2017-11-16 v0.8.18
* 解决使用 server.mfs 方法时，因 webpack 未打包好html文件造成的时序问题
* 更新 webpack-dev-server

### 2017-11-15 v0.8.17
* 解决 pageEntrys 中 htmlsrc 使用同样的模板，导致 server.mfs 无法通过源路径找到生成的html的问题

### 2017-11-8 v0.8.15
* 解决 .cache-loader 找不到的时序问题

### 2017-11-2 v0.8.14
* node端代码打包也支持profile查看打包后的模块了
* 解决服务端代码external外部模块找不到模块的问题

### 2017-11-1 v0.8.13
* 修复了路由挂载post请求无效的问题。
  serve-index 会过滤掉所有的非 `GET` 和 `HEAD` 请求，需要在此之前处理 koa-router 的挂载

### 2017-10-30 v0.8.12
* 调整了koa router中间件的挂载位置，使不影响koa其他中间件的挂载（setup和before等）
* 更换了koa中的 connect-history-api-fallback

### 2017-10-30 v0.8.10
* 优化了对模板html的读取，现抽象出 server.mfs 方法用于读取html文件

### 2017-10-24 v0.8.7
* dll 文件自动插入html，无需再手动引用

### 2017-10-19 v0.8.4
* serverEntry 模块支持 es6 的 export default 形式

### 2017-10-19 v0.8.1
* webpack-dev-server 增加配置，支持在使用webpack--dev-middleware 之前和之后配置中间件

### 2017-10-18 v0.8.0
* 支持 SSR， 服务端 js 支持热更新
* webpack-dev-sever 扩展支持 Koa2

### 2017-08-09 v0.7.3
* 更新依赖库版本
* 更新webpack-dev-server到2.8.0

### 2017-08-09 v0.7.0
* 修复windows下项目配置文件tua.js在命令执行时会被系统默认打开的问题，改为更加合理的 .tuarc，tua命令在windows下会优先打开同名文件
**注意: 旧项目中的 tua.js 会被自动重新命名为 .tuarc，请注意提交 .tuarc 到代码仓库。** 

### 2017-08-03 v0.6.5
* 增强 cssEnhance 配置的能力，支持本地css loader，支持自定义postcss配置

### 2017-08-02 v0.6.4
* 修复 postcss 配置文件在 windows 中的生成的路径问题

### 2017-07-31 v0.6.3
* 去掉 webpack-chunk-hash 插件，此插件会导致内容不同的 manifest 文件名重名问题

### 2017-07-26 v0.6.1
* webpack 版本升级到 v3.4.1
* uglify 版本升级到 v3.0.6
* extract-text-webpack-plugin 版本升级到 v3.0.0

### 2017-07-26 v0.5.29
紧急修复 chunk-manifest-webpack-plugin v1.1.1 版本带来的 bug，暂时固定版本到 1.1.0
error 如下：
```shell
ERROR in chunk manifest [entry]
scripts/[name]_[chunkhash]_aaa.js
Chunk.entry was removed. Use hasRuntime()
```
