UNPKG

roadhog-extra

Version:

Cli tool for serve and build react app, based on create-react-app, support JSON pattern config.

648 lines (469 loc) 19.3 kB
# roadhog [![NPM version](https://img.shields.io/npm/v/roadhog.svg?style=flat)](https://npmjs.org/package/roadhog) [![Build Status](https://img.shields.io/travis/sorrycc/roadhog.svg?style=flat)](https://travis-ci.org/sorrycc/roadhog) [![NPM downloads](http://img.shields.io/npm/dm/roadhog.svg?style=flat)](https://npmjs.org/package/roadhog) [![Dependencies](https://david-dm.org/sorrycc/roadhog/status.svg)](https://david-dm.org/sorrycc/roadhog) [View README in English](./README_en-us.md) roadhog 是一个 cli 工具,提供 `server`、 `build` 和 `test` 三个命令,分别用于本地调试和构建,并且提供了特别易用的 [mock 功能](#mock)。命令行体验和 create-react-app 一致,配置略有不同,比如默认开启 [css modules](https://github.com/css-modules/css-modules),**然后还提供了 [JSON 格式的配置方式](https://github.com/sorrycc/roadhog#配置)**。 * [介绍 roadhog —— 让 create-react-app 可配的命令行工具](https://github.com/sorrycc/blog/issues/15) * [从 atool-build + dora 到 roadhog](https://github.com/sorrycc/blog/issues/17) --- <p align="center"> <img src="https://zos.alipayobjects.com/rmsportal/vpkwOtXNukXpeQBNToEb.gif" width="926" height="521" /> </p> ## Why roadhog 由于 [create-react-app](https://github.com/facebookincubator/create-react-app) 的默认配置不能满足需求,而他又不提供定制的功能,于是基于他实现了一个可配置版。所以如果既要 create-react-app 的优雅体验,又想定制配置,那么可以试试 roadhog 。 ## Getting Started ### 安装 ```bash $ npm i roadhog -g ``` ### 使用 本地开发 ```bash $ roadhog server ``` 打包发布 ```bash $ roadhog build ``` 测试,默认会跑 `./test` 目录下的所有文件 ```bash $ roadhog test ``` ## 特性 ### 错误处理 感谢 create-react-app,roadhog 在错误处理上有着良好的体验。此外,roadhog 针对 `.roadhogrc` 的解析错误也做了优化。 #### .roadhogrc 解析错误 <img src="https://zos.alipayobjects.com/rmsportal/wPGMQwhZmFhGddMZKFci.png" width="809" height="585" /> #### 语法错误 控制台 <img src="https://zos.alipayobjects.com/rmsportal/BWnfDJQqlnGvHSZxOVuY.png" width="809" height="585" /> 浏览器 <img src="https://zos.alipayobjects.com/rmsportal/onzXGetQRKGmWQXmICDC.png" width="893" height="751" /> #### 运行时错误 没有捕获,在浏览器的控制台查看。 #### .roadhogrc.mock.js 解析错误 <img src="https://zos.alipayobjects.com/rmsportal/awkFmHoxLWdRgbTlCzDF.png" width="745" height="551" /> ### HMR (热替换) CSS 在开发模式下会走 style-loader (被内嵌在 JavaScript 文件中),所以只要保证 JavaScript 的热更新,即可实现 CSS 的热更新。 如果大家使用 [dva](https://github.com/dvajs/dva) ,配上 [babel-plugin-dva-hmr](https://github.com/dvajs/babel-plugin-dva-hmr) 即可实现 routes 和 components 以及相关 CSS 修改的热更新,其他修改会自动刷新页面。 ```json "env": { "development": { "extraBabelPlugins": ["dva-hmr"] } } ``` ### Mock roadhog server 支持 mock 功能,类似 [dora-plugin-proxy](https://github.com/dora-js/dora-plugin-proxy),在 `.roadhogrc.mock.js` 中进行配置,支持基于 require 动态分析的实时刷新,支持 ES6 语法,以及友好的出错提示。 比如: ```js export default { // 支持值为 Object 和 Array 'GET /api/users': { users: [1,2] }, // GET POST 可省略 '/api/users/1': { id: 1 }, // 支持自定义函数,API 参考 express@4 'POST /api/users/create': (req, res) => { res.end('OK'); }, // Forward 到另一个服务器 'GET /assets/*': 'https://assets.online/', // Forward 到另一个服务器,并指定子路径 // 请求 /someDir/0.0.50/index.css 会被代理到 https://g.alicdn.com/tb-page/taobao-home, 实际返回 https://g.alicdn.com/tb-page/taobao-home/0.0.50/index.css 'GET /someDir/(.*)': 'https://g.alicdn.com/tb-page/taobao-home', }; ``` ### 智能重启 配置文件修改的修改会触发 roadhog server 的自动重启,会触发重启的文件有: * `.roadhogrc` * `.roadhogrc.js` * `.roadhogrc.mock.js` * theme 配置指定的文件 ## 配置 关于配置的一些基本概念: * 配置存于 `.roadhogrc` 文件中(如果你不喜欢 JSON 配置,可以用 `.roadhogrc.js` 以 JS 的方式编写,支持 ES6) * 格式为 `JSON`,允许注释 * 布尔类型的配置项默认值均为 `false` * 支持通过 `webpack.config.js` 以编码的方式进行配置,但不推荐,因为 roadhog 本身的 major 或 minor 升级可能会引起兼容问题。使用时会给予警告⚠️⚠️⚠️,详见 [#36](https://github.com/sorrycc/roadhog/issues/36) 。(`webpack.config.js` 本身的编写支持 ES6,会通过 babal-register 做一层转换。) 默认配置: ```js { "entry": "src/index.js", "disableCSSModules": false, "cssModulesExclude": [], "publicPath": "/", "htmlTemplates": [], "assetsPath": { "media": "assets/media/", "js": "assets/js/", "css": "assets/css/", "img": "assets/images/", }, "copyConfig": [ { "from": "./public", "to": "./dist" } ], "babelExclude": [], "outputPath": "./dist", "extraBabelPlugins": [], "extraPostCSSPlugins": [], "sass": false, "hash": false, "autoprefixer": null, "proxy": null, "externals": null, "library": null, "libraryTarget": "var", "multipage": false, "define": null, "env": null, "theme": null, "doneCallback": (config, paths) => { console.log("all done") }, } ``` 查看更多[配置相关问题和改进](https://github.com/sorrycc/roadhog/issues?q=is%3Aissue+is%3Aopen+label%3Aconfig)。 ### entry 指定 webpack 入口文件,支持 [glob](https://github.com/isaacs/node-glob) 格式。 如果你的项目是多页类型,会希望把 `src/pages` 的文件作为入口。可以这样配: ``` "entry": "src/pages/*.js" ``` ### disableCSSModules 禁用 [CSS Modules](https://github.com/css-modules/css-modules)。最好别关,熟悉并使用他后,你会发现写样式简单了很多。 ### cssModulesExclude 支持 CSSModules 混用,通过 cssModulesExclude 可指定不需要走 CSSModules 的文件列表。 ``` "cssModulesExclude": [ './src/a.css', './src/b.less', ] ``` ### hash 使用 hash 文件名。 ``` "hash": true ``` ### publicPath 配置生产环境的 [publicPath](http://webpack.github.io/docs/configuration.html#output-publicpath),开发环境下永远为 `/`。 ### htmlTemplates 配合多入口应用设置不同的页面,具体配置参考[html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 示例: ```js { "htmlTemplates": [ { inject: false, template: require('html-webpack-template'), appMountId: "root", scripts: [ "http://res.wx.qq.com/open/js/jweixin-1.2.0.js" ], lang: "zh-CN", mobile: true, title: 'title', hash: false, links: [ { href: IMG_BASE + 'assets/favicon.ico', rel: 'shortcut icon' } ], filename: DEBUG ? 'index.html' : "index.ftl", bodyHtmlSnippet: '', "window": windowVars, chunks: ['index', 'common'], minify: { collapseWhitespace: true, conservativeCollapse: true, preserveLineBreaks: true, removeComments: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, { inject: true, template: 'src/demo.ejs', hash: false, favicon: 'public/favicon.ico', filename: 'demo.html', chunks: ['demo', 'common'], } ] } ``` ### assetsPath 资源输出路径,默认: 图片资源:assets/img css文件:assets/css js文件:assets/js 其他文件: assets/media ```js { "assetsPath": { "media": 'assets/media/', "js": 'assets/js/', "css": 'assets/css/', "img": 'assets/images/', }, } ``` ### copyConfig 执行文件的复制,详细配置请参考https://github.com/webpack-contrib/copy-webpack-plugin配置 注意这里使用的webpack-plugin所以是不能复制编译完毕的文件到其他目录中 如果想在编译完毕后做一些操作,请参考配置:doneCallback ```js { "copyConfig": [ { "from": "./public", "to": "./dist", "force": true, } ], } ``` ### doneCallback 在编译完毕后做一些操作(比如复制文件到指定的目录), doneCallback必须为回调函数 传递两个参数: config:配置信息 paths:{ appBuild: resolveApp('dist'), appPublic: resolveApp('public'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appNodeModules: resolveApp('node_modules'), ownNodeModules: resolveOwn('../../node_modules'), dllNodeModule: resolveApp('node_modules/roadhog-dlls'), dllManifest: resolveApp('node_modules/roadhog-dlls/roadhog.json'), appBabelCache: resolveApp('node_modules/.cache/babel-loader'), resolveApp, appDirectory, } ```js import fs from 'fs-extra'; import path, {resolve} from 'path'; import glob from 'glob'; { "doneCallback": (config, paths) => { console.log("all done"); const appDirectory = paths.appDirectory; const baseSrcPath = path.resolve(appDirectory, "./dist") glob(baseSrcPath + "/**/*.ftl", function (er, files) { // files is an array of filenames. // If the `nonull` option is set, and nothing // was found, then files is ["**/*.js"] // er is an error object or null. // console.log(files) files.forEach((file) => { const tmpDir = path.relative(baseSrcPath, file); // console.log(baseSrcPath, file, tmpDir) fs.copySync(file, path.resolve(appDirectory, "../webapp/", tmpDir) ) }) }) fs.copy(path.resolve(appDirectory, "./dist/assets"), path.resolve(appDirectory, "../webapp/") ) }, } ``` ### babelExclude 用于babel排除文件配置,与extraBabelIncludes相互配合使用 ### outputPath 配置[输出路径](http://webpack.github.io/docs/configuration.html#output-path),默认是 `./dist`。 ### extraBabelPlugins 配置额外的 babel plugin。babel plugin 只能添加,不允许覆盖和删除。 比如,同时使用 antd, dva 时,通常需要这么配: ``` "extraBabelPlugins": [ "transform-runtime", "dva-hmr", ["import", { "libraryName": "antd", "libraryDirectory": "lib", "style": "css" }] ] ``` 同时安装相关依赖: ```bash $ npm i babel-plugin-transform-runtime babel-plugin-import babel-plugin-dva-hmr --save-dev $ npm i babel-runtime --save ``` 注意:这么配还有个问题,`dva-hmr` 是开发环境的插件,如果 build 时也用上就会打出冗余代码。解决方案详见 [#env](#env)。 ### extraPostCSSPlugins 配置额外的 postcss 插件。 注意:由于 postcss 的插件是以函数的方式进行配置的,所以这个配置只能在 `.roadhogrc.js` 里使用。 比如: ``` extraPostCSSPlugins: [ pxtorem({ rootValue: 100, propWhiteList: [], }), ], ``` ### autoprefixer 配置 autoprefixer 参数,详见 [autoprefixer](https://github.com/postcss/autoprefixer) 和 [browserslist](https://github.com/ai/browserslist#queries)。 比如,如果是做移动端的开发,可以配成: ``` "autoprefixer": { "browsers": [ "iOS >= 8", "Android >= 4" ] } ``` ### sass 支持 sass,值为 [node-sass](https://github.com/sass/node-sass#options) 的配置参数。 注意:开启 sass 支持需在项目代码中安装 node-sass 和 sass-loader 两个依赖。 ### proxy 配置代理,详见 [webpack-dev-server#proxy](https://webpack.github.io/docs/webpack-dev-server.html#proxy)。 如果要代理请求到其他服务器,可以这样配: ``` "proxy": { "/api": { "target": "http://jsonplaceholder.typicode.com/", "changeOrigin": true, "pathRewrite": { "^/api" : "" } } } ``` 然后访问 `/api/users` 就能访问到 http://jsonplaceholder.typicode.com/users 的数据。 如果要做数据 mock,可以考虑和 [json-server](https://github.com/typicode/json-server) 结合使用,把 `/api` 代理到 json-server 启动的端口。 ### externals 配置 webpack 的 [externals](http://webpack.github.io/docs/configuration.html#externals) 属性。 ### library 配置 webpack 的 [library](http://webpack.github.io/docs/configuration.html#output-library) 属性。 ### libraryTarget 配置 webpack 的 [libraryTarget](http://webpack.github.io/docs/configuration.html#output-librarytarget) 属性。 ### multipage 配置是否多页应用。多页应用会自动提取公共部分为 common.js 和 common.css 。 ### define 配置 webpack 的 [DefinePlugin](http://webpack.github.io/docs/list-of-plugins.html#defineplugin) 插件,define 的值会自动做 `JSON.stringify` 处理。 ### env 针对特定的环境进行配置。server 的环境变量是 `development`,build 的环境变量是 `production`。 比如: ``` "extraBabelPlugins": ["transform-runtime"], "env": { "development": { "extraBabelPlugins": ["dva-hmr"] } } ``` 这样,开发环境下的 extraBabelPlugins 是 `["transform-runtime", "dva-hmr"]`,而生产环境下是 `["transform-runtime"]`。 ### theme 配置主题,实际上是配 less 的 `modifyVars`。支持 Object 和文件路径两种方式的配置。 比如: ``` "theme": { "@primary-color": "#1DA57A" } ``` 或者, ``` "theme": "./node_modules/abc/theme-config.js" ``` 这里有 [如何配置 antd theme 的例子](https://github.com/dvajs/dva-example-user-dashboard/commit/d6da33b3a6e18eb7f003752a4b00b5a660747c31) 。 ### svgSpriteLoaderDirs Notice: - roadhog 版本必须 >= `0.6.0-beta1`。 - 因为 `.roadhogrc` 配置文件优先级大于 `.roadhogrc.js`, 请先删除 `.roadhogrc`。 配置一个路径数组, 该路径下的 svg 文件会全部交给 [svg-sprite-loader](https://github.com/kisenka/svg-sprite-loader) 处理 比如,使用 antd-mobile@1 的 [自定义 svg icon](https://mobile.ant.design/components/icon) 功能的用户,可以在 `.roadhogrc.js` 文件中做如下配置 ```js const path = require('path'); const svgSpriteDirs = [ require.resolve('antd-mobile').replace(/warn\.js$/, ''), // antd-mobile 内置svg path.resolve(__dirname, 'src/my-project-svg-foler'), // 业务代码本地私有 svg 存放目录 ]; export default { // ... svgSpriteLoaderDirs: svgSpriteDirs, //... } ``` ## 环境变量 可环境变量临时配置一些参数,包括: * `PORT`, 端口号,默认 8000 * `HOST`, 默认 localhost * `HTTPS`,是否开启 https,默认关闭 * `BROWSER`,设为 none 时不自动打开浏览器 * `CLEAR_CONSOLE`,设为 none 时清屏 比如,使用 3000 端口开启服务器可以这样: ```bash # OS X, Linux $ PORT=3000 roadhog server # Windows (cmd.exe) $ set PORT=3000&&roadhog server # Or use cross-env for all platforms $ cross-env PORT=3000 roadhog server ``` ## 命令行参数 ### roadhog server ```bash $ roadhog server -h Usage: roadhog server [options] Options: -h Show help [boolean] ``` ### roadhog build ```bash $ roadhog build -h Usage: roadhog build [options] Options: --debug Build without compress [boolean] [default: false] --watch, -w Watch file changes and rebuild [boolean] [default: false] --output-path, -o Specify output path [string] [default: null] --analyze Visualize and analyze your Webpack bundle. [boolean] [default: false] -h Show help [boolean] ``` ### roadhog test ```bash $ roadhog test -h Usage: roadhog test [options] [mocha-options] Options: --coverage Output coverage [boolean] [default: false] -h Show help [boolean] ``` ## 使用 `public` 目录 我们约定 `public` 目录下的文件会在 server 和 build 时被自动 copy 到输出目录(默认是 `./dist`)下。所以可以在这里存放 favicon, iconfont, html, html 里引用的图片等。 ## FAQ ### 那么为什么提供 JSON 级别的约定型配置,而非类似 webpack.config.js 的编码型配置? 首先是 JSON 的方式比较简单,`true`/`false` 或是一些简单的字符串就可完成配置;另外,JSON 方式能有效控制使用场景,而编程式的非常不可控,roadhog 的一个简单改动都可能导致之前的配置不可用。 ### 为什么叫 roadhog ? roadhog 即路霸,和 [dva](https://github.com/dvajs/dva) 一样,是守望先锋中的另一名英雄,希望能为 dva 保驾护航。 <img src="https://zos.alipayobjects.com/rmsportal/guCnwwMItoLOTmcdbaEZ.png" width="200" height="200" /> ### 报 `Unexpected token` 错误,类似下面这样 ``` Error in ./index.js Module parse failed: /Users/chencheng/Documents/Work/Misc/dva-cli/boilerplates/demo/index.js Unexpected token (15:23) You may need an appropriate loader to handle this file type. SyntaxError: Unexpected token (15:23) @ multi index ``` 把源码放到 src 目录下,因为非 src 目录下的文件不会走 babel 编译。 ### Windows/Ubuntu 下每次启动后打开新 Tab 比较烦 ```bash # Mac, Ubuntu $ BROWSER=none roadhog server # Windows $ set BROWSER=none&&roadhog server # Or use cross-env for all platforms $ cross-env BROWSER=none roadhog server ``` ## LICENSE MIT ## CHANGE LOG 1. doneCallback 参数 用于编译完成后的文件复制等操作 1. copyConfig 参数 用于拷贝其他一些多余的文件,再webpack执行的时候,使用插件https://github.com/webpack-contrib/copy-webpack-plugin,注意,此参数是在webpack执行中间执行的,上面的doneCallback参数实在webpack执行完毕后执行的 1. htmlTemplates 参数 使用[html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin)来支持多文件 包括不同的文件切割,自定义模板,具体请参考 htmlTemplates配置 1. assetsPath 参数 配置各类型文件目录结构,用于归类 资源输出路径,默认: 图片资源:assets/img css文件:assets/css js文件:assets/js 其他文件: assets/media