第一章:搭建react开发环境

当我们抛开React其生态中的其他库(Redux,React-Router)来看,它本身仅仅是由少量API构成的一个Web库。

打造kodo的目标是希望大家可以通过简单的UI库来重新认识React其本身,而不是夹杂在其他东西中去学习它。我们的目标是使用最新的ES2015来编写完我们的UI库,并且使用了React 15.0.2版本做为基础。

使用到的工具

Webpack

正如官网对 Webpack 的描述,它是一种模块化加载器,当然也不仅仅限于此。某种程度上来说,可以代替某些gulp的功能,至少有些还是无法替代的。在webpack中所有的资源都会被视作模块来处理,为了应对这样的情况,webpack有对应的loader机制来处理,另外shim,plugins,和其他构建工具,一样一样的,更多的细节,需要你在实际的应用中慢慢去体会了。

你可以阅读如下两篇文章:

Babel

Babel 是一个 JavaScript 编译器,用于将你的ES2015代码转换成ES5跑在浏览器中。

NPM包依赖管理

做为Node世界里的包管理器,我想大家从Grunt时代起就已经熟练的使用npm install命令来安装一些依赖完成前端自动化构建任务。

更多的信息你可以通过阅读玩转NPM来增加理解。

nodemon和koa

nodemon可以用来监控文件并且重启Node服务器,koa是Node世界里的一个Web开发框架。由于kodo项目用koa写了一个静态服务器,所以且需要使用它。如果你有browser-sync的使用经验,你可以替换成它。(请原谅我的偷懒)

React Dev Tools

调试工具:React Dev Tools

开始行动

  • 将工具--save-dev到应用开发环境
  • 将react,react-dom,classnames,normalize.css --save到你的应用依赖环境
  • 如果你需要漂亮的icon,请求引用ionic提供的icon库

你所需要的工具列表:

"devDependencies": {
  "babel-core": "^6.8.0",
  "babel-loader": "^6.2.4",
  "babel-preset-es2015": "^6.6.0",
  "babel-preset-react": "^6.5.0",
  "css-loader": "^0.23.1",
  "extract-text-webpack-plugin": "^1.0.1",
  "koa": "^1.2.0",
  "koa-logger": "^1.3.0",
  "koa-static": "^2.0.0",
  "less": "^2.6.1",
  "less-loader": "^2.2.3",
  "nodemon": "^1.9.2",
  "webpack": "^1.13.0"
}

你的应用依赖环境:

"dependencies": {
  "classnames": "^2.2.5",
  "normalize.css": "^4.1.1",
  "react": "^15.0.2",
  "react-dom": "^15.0.2"
 }

使用npm install xxx命令来安装它们吧。

kodo项目已经使用了package.json文件来管理依赖,如果你是在跑kodo项目,请直接npm install 即可。

目录结构说明

总体而言kodo项目的目录结构分为了binsrctestexamples四个目录。

  • bin目录中放置了Webpack所使用的配置文件webpack.config.js
  • src目录少许复杂,内部又分了index.js入口文件,util工具函数目录,components组件放置的目录,stylesheets less文件放置的目录
  • test目录放置了单元测试文件
  • examples目录放置了demo的html文件

Webpack配置说明

var path = require('path');
var webpack = require('webpack');
var plugins = [];
var env = process.env.NODE_ENV;
var containerPath = path.resolve('.');

var config = {
    entry: './src/index.js',
    devtool: 'source-map',
    output: {
        path: path.resolve(containerPath,'dist/'),
        filename: 'kodo.js',
        library: 'Kodo',
        libraryTarget: 'umd'
    },
    module:{
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
          presets: ['react','es2015']
        }
            }
        ]
    },
    externals: [
        {
            'react': {
                root: 'React',
                commonjs2: 'react',
                commonjs: 'react'
            }
        },
        {
            'react-dom': {
                root: 'ReactDOM',
                commonjs2: 'react-dom',
                commonjs: 'react-dom'
            }
        }
    ],
    extensions: ['', '.js', '.css', '.scss', '.jade', '.png', '.jpg'],
    plugins:plugins
};

module.exports = config;

if (env === 'production') {
    config.plugins.push(new webpack.DefinePlugin({
        'process.env': {
            'NODE_ENV': JSON.stringify(env)
        }
    }));
    config.devtool = 'eval-source-map';
    config.output.filename = 'kodo-min.js';
}

这里主要通过NODE_ENV参数production来区分dev环境还是需要压缩的环境,在这里你只需要关注配置好babel即可。

How Run?

现在你可以运行npm run devnpm run dev-server来启动webpack的构建和一个web服务器,如果你使用了npm run dev-server,你还需要在启动命令之前安装nodemon(建议全局安装)。

创建一个React组件

Mask蒙板为例,如果你已经成功运行了kodo项目,你可以访问http://127.0.0.1:3001/examples/dialog.html,点击一个任意的对话框,查看Mask组件的效果。

  1. components中创建一个mask目录,并且在mask目录中创建index.js文件。

因为mask是一个非常简单的组件,所以我用函数来编写,不继承React.Componet

import classNames from 'classnames';

function Mask(props){
  const { type } = props;
  const css = classNames({
    'overlay active': true,
    ['overlay-'+ type]: !!type
  });
  return (
    <div className={ css }></div>
  );
}

export default Mask;

最后你可以在dialog中查看使用的方式(Mask):

import React,{ PropTypes } from 'react';
import classNames from 'classnames';
import Mask from '../mask/';
import Alert from './Alert';
import Confirm from './Confirm';

const propTypes = {
  type: PropTypes.string,
  show: PropTypes.bool,
  title: PropTypes.string,
  buttons: PropTypes.array,
}

const defaultProps = {
  type: 'alert',
  show: false,
  title: '',
  buttons: []
}

class Dialog extends React.Component {

  render (){
    const { type, show, className, title } = this.props;
    const css = classNames({
      'dialog-wrap': true,
      'active': show,
      [className]: className
    });
    const Component = type === 'alert' ? Alert : Confirm;
    return (
      <section
        className={ css }
      >
        <Mask type="dialog"/>
        <Component {...this.props }/>
      </section>
    );
  }
}

Dialog.propTypes = propTypes;
Dialog.defaultProps = defaultProps;

export default Dialog;

results matching ""

    No results matching ""