基于es6,使用react、webpack、babel构建模块化javascript应用 -pg电子游戏网站

【编者按】本文为《》的简译内容,讲述了作者基于es6,使用react、webpack、babel构建模块化javascript应用的编程心得。

如果你想用react构建一个新的javascript应用,而且你还想实践es6语法中的新特性,此外,你甚至想创建一些可重用组件并发布到npm上,那么你究竟应该怎样实现这些需求?你如何将es6代码发布到npm,又如何在后续的项目中使用这些代码?我花了一些时间解决上面这些问题,现在我愿意与你们分享我习得的新知识。

如果你真的不希望阅读所有的细节,只想看看代码最终的效果——可以直接阅读最后一部分。

需求

我们先来搞清楚我们到底想要得到什么,应该如何去实现。

我们的主要目标是:基于es6,使用我们自定义的react组件创建一个react应用。其中最棘手的部分是自定义react组件。以下是实现这些目标的需求列表:

1.自定义组件应该使用es6编写;
2.自定义组件应该完全自给自足(使用方法足够简单:安装,导入,渲染);
3.自定义组件应该提供自身所需的样式(参考第2条,自给自足);
4.自定义组件应该通过安装(因为bower有很多问题);
5.最后——所有自定义组件应该有单元测试和代码覆盖率报告;
6.加分项——自定义组件不应该相互依赖,但是应该能够相互影响。
此外,我们需要一些很棒的调试工具,例如:代码检查、源码映射(因为代码需要编译,所以这是调试的必要工具)。
处理需求

现在我们已了解所有需求,可以开始寻找满足这些需求的方法。所以,首先需要选定我们将使用的工具集和相关库。

编译

我们要基于es6开发应用,目前的浏览器,所以我们需要将es6编译为es5。同时我们希望通过npm管理自定义组件,需要选用一个兼容commonjs的工具集。

目前有两种流行的可用选择——和。二者都满足我们的大部分需求,考虑到我们的项目需要使用样式文件,而webpack对非javascript文件(例如:样式文件、图片、字体文件)非常友好,所以最终我们将选用webpack。

webpack已经能够满足大部分需求,我们将在此基础上加入,帮助我们完成更多任务(例如:单元测试、代码覆盖率检测、静态资源伺服)。

使用es6

现在我们已经知道如何使用webpack和gulp.js来构建代码,可是如何才能满足我们的第一个需求——使用es6?我们可以使用转译器,帮助我们将es6代码转译为主流浏览器支持的es5代码。目前流行的转译器有:、、(勉强算是),我们将选用babel.js,它有一个更好的生态系统(插件、扩展等)。如果你尚不知晓其为何物,请记住这是一个非常棒的项目,我推荐你阅读它们的文档。最棒的是,babel.js不仅支持es6语法,它还可以编译jsx,所以我们可以在编译步骤彻底弃用标准react jsx编译器了!

如果你只想使用babel.js,我推荐你阅读它们的。axel rauschmayer博士曾经撰写,也值得一读,如果你对javascript感兴趣,我也极力推荐订阅他的博客。

自给自足

现在我们选定了es6转译器,让我们讨论一下自给自足的问题。如果我们开发纯react组件——那么可以轻松地让它们独立工作(可重用),你甚至可以参考官方指南学习编码方式。但如果我们需要在组件内提供默认的自身样式,需要怎样实现呢?

当然,我们可以选择“纯js”方法向我们的jsx文件加入内联样式,就像这样:
const render = function() {
  const defaultstyle = {
    color: 'red',
  };
  
  return (
    
i have inline styles
); };

jsx内联样式

这个方法存在一个问题,我们几乎无法通过父应用控制这个组件的样式。而且,如果我们需要加载图片或自定义字体文件,这个方法就会失效。所以,是否有更好的方法呢?

webpack可以帮你解决这个问题!幸运的是,webpack 加载器可以加载许多类型的文件。其背后的思想非常简单——在加载过程中动态地对载入文件进行可插拔转换。从本质上来说,加载器为我们处理各种文件。我们将选用一个特殊的babel-loader来将我们的es6代码转译为es5代码。

但最酷的是,加载器可以处理任何文件。所以,如果我们想加载样式——我们只需要添加style-loader!最终,我决定使用less,它稍微复杂一些——我将创建如下的加载链:
  • 首先,使用less-loader处理*.less文件,将其转换为css;
  • 然后,使用css-loader将编译好的css传递给下一个步骤;
  • 最后,使用style-loader将最终的样式引入到生成的代码中。

通过这个加载链,我们可以使用less编写组件的样式,下面这段代码演示了这种组件的入口点:
import './style/style.less';
import component from './src/component';
 
export default component;

借助webpack将样式引入到javascript中


正如你所见,加载样式像导入文件一样简单。的确,由less-loader、css-loader以及style-loader构成的加载链必须要在我们的webpack配置文件中提前配置好(参考下一节的第一个示例)。

现在我们可以从相互独立的组件中加载样式,但是css默认使用全局变量,这意味着如果两个组件中使用了相同的类名,其中一个将被改写,我们如何回避这个问题呢?

我能想出来的最简单的方法是:在html标签和样式文件中,使用组件名称作为最外层元素的类名,人为地创建组件的作用域。就像这样:
.component-name {
  span {
    color: red;
  }
}
const render = function() {
  return (
    
i have scoped styles
); };

组件样式的人为作用域


如此一来,所有组件将拥有唯一命名,当他们被封装进同一个应用中时不再产生冲突,能够很好地协同工作。而且,当我们想在应用层重新定义组件样式时,可以使用组件命名作为类名直接改写。

发布到npm

接着,你如何将es6模块发布到npm上呢?事实上,你无须这样做。至少目前还不需要。你可以直接向外发布你的原生代码,但这通常是一个糟糕的想法,当你后续想将代码引入到主应用或其它组件中时会感到非常痛苦。当然,你可以通知webpack(同样也可以通知browserify)来编译需要用到的代码。但是,如果这样做,你不得不使用webpack(以及浏览器)来运行各种测试,我通常在命令行中运行测试,因为这样运行速度更快,并且便于后续的自动化测试封装(也就是我们常说的持续集成)。

目前我在项目中应用的最好方法是——同时传送原生es6代码和编译后的es5代码,实现这个方法非常简单:
  • 向你的package.json文件添加构建指令;
  • 在预发布阶段运行构建指令;
  • 使用编译后的es5代码作为主文件;
  • 通过package.json文件的额外字段暴露es6代码。

它看起来是这样的:
{
  "name": "es6-component",
  "version": "1.0.0",
  "description": "my awesome es6 component",
  "main": "es5/component.js",
  "es6": "index.js",
  "scripts": {
    "build": "gulp build",
    "prepublish": "npm run build"
  }
}

将es6模块发布到npm上的package.json

这种方法有两个优点:
1.在所有es5代码中,我们可以轻松地引入或require()这个模块,它能够正常工作!
2.如果我们出于某些原因需要用到模块的源代码,我们同样可以轻松地通知webpack使用“es6”字段来加载或引入es6代码。
单元测试及代码覆盖率

你必须佩服的是,在babel中配置单元测试和代码覆盖率检测非常简单(得益于babel伟大的生态系统,正如我之前提到的那样)。
--compilers: jsx?:babel/register

我一直使用作为测试工具,所以我会讲解如何将其应用到项目中。支持es6代码非常简单,你只需在执行mocha指令时添加一个编译flag(或添加到mocha配置文件)就可以通知mocha使用babel预编译器:

完成这一步之后,就可以在es6代码中运行测试了,当然你也可以使用es6来编写测试文件!

现在要处理最棘手的部分——我们有了react组件,我们想使用mocha完成测试,却又不想在浏览器中运行测试(可以运行一个,但是它非常繁重),我们应该如何去做呢?

答案就是——基于用javascript实现了whatwg的dom和html标准。它比phantom更轻量,并且满足几乎所有我们测试react所需的功能。

以下是为react配置jsdom环境的测试helper文件的示例:
import localstorage from 'localstorage';
import {jsdom} from 'jsdom';
 
// init jsdom
global.document = jsdom();
global.window = global.document.defaultview;
global.navigator = global.window.navigator;
 
// local storage polyfill
global.window.localstorage = localstorage;
global.localstorage = localstorage;
 
// import react after dom
const react = require('react/addons');
 
before(function() {
    // expose react and testutils
    this.react = react;
    this.testutils = react.addons.testutils;
});
 
beforeeach(function() {
    // create container
    this.container = global.window.document.createelement('div');
});
 
aftereach(function(done) {
    // clean jsdom
    this.react.unmountcomponentatnode(this.container);
    // timeout
    settimeout(done);
});

在命令行中运行react测试的jsdom环境


注意我使用import声明引入jsdom和localstorage,但却使用require()加载react,这是因为import声明会被提前,我们需要确保在jsdom初始化之后加载react。如果你尝试在dom就绪前加载react,那么直到你与组件进行交互时它才会开始工作,然后你得到的往往是各种各样的错误,因为react假设这属于非浏览器环境,不使用dom相关特性。

现在我们有了正确运行的mocha测试,我们也可以轻松获取istanbul覆盖率检测工具并正常执行:
istanbul cover _mocha -- -r spec

组件交互

接下来实现我们的加分需求——无相互依赖的交互。这一部分内容来自于我正从事的一个项目,如果你不太感兴趣,大可跳过这一节。

当然,如果你依然感兴趣,那让我们一起讨论一下实现这个目标的方法。

我们需要使松耦合的系统中各部分相互交流,在完美的实现中它们甚至无须知道相互的存在,只须响应请求。这样的任务听起来是否非常熟悉?

你或许曾经听说过微服务这个概念,你甚至可能已经使用过它们。如果你对微服务所知甚少,我推荐你看一下。

如果你懒得看(或者想稍后看)他的演讲,那么简单了解一下微服务的思想:许多小规模、独立的,通过通用接口相互交流的离散服务实体。通用接口可以有多种形式,其中包括:消息总线、表征状态传输(rest,又称表征状态转移)、远程过程调用(rpc)等。

因为我们做的是客户端javascript应用,在接口问题上我们的确没有那么多的选择。幸运的是,有一个非常赞的库,它专门处理类似这样的情况——postal.js。

即使它仍然基于回调函数实现底层功能,但是它将消息分为channel和topic两类,提供了非常大的弹性。

通过示例演示所有的这一切是如何工作的,十分容易。

想象一下我们有一个app需要一些认证和url签名功能来获取数据。通过postal我们可以定义一个认证channel,它将会监听那些签名请求,并通过不同的topic返回已签名的url,就像这样:
import postal from 'postal';
// get postal channel for current component
const channel = postal.channel("auth");
 
const signurl = () => {
  // signing code here
};
 
// listen to sign requests
const signaction = channel.subscribe("url.sign", function(url, envelope) {
  const signedurl = sign;
  channel.publish("url.signed", signedurl);
});
import postal from 'postal';
// get postal channels
const channel = postal.channel("query");
const authchannel = postal.channel("auth");
// define data fetching stuff
const requesturl = 'http://...';
const getdata = () => {
  // data-fetching logic here
};
// listen for data requests
const allitemsaction = channel.subscribe("items.all", () => {
  // wait for signed url
  authchannel.subscribe("url.signed", (signedurl) => {
    const data = getdata(signedurl);
    channel.publish("items.data", data);
  });
  authchannel.publish("url.sign", requesturl);
});

在组件中使用postal.js的channels进行通信


这段代码可以很好地工作,因为我们无须了解任何有关其它组件的信息——我们只须了解使用哪个channel和topic。一方面,这意味着管理这些内容的负担落到开发者身上;另一方面,在这种实现的基础上,我们可以轻松地更换认证组件——今天我们使用oauth,明天我们使用自定义token系统,以后使用其它功能,我们只须更换一下认证组件就可以支持新的工作流。

代码检查和源码映射(source map)

最后,我们再为项目加入一些小改进:支持代码检查,启用源码映射。

jshint不支持es6和react代码,我们将使用eslint代替它。eslint支持javascript和jsx的语法,并可以通过插件进行扩展。

将之于webpack结合非常容易,你只须在你的webpack配置文件中添加几行代码。下面这个代码片段展示了所需的配置:
var path = require('path');
 
module.exports = {
    devtool: 'inline-source-map',
    debug: true,
    // your other props here
    // ...
    module: {
      preloaders: [
        {
          test: /\.jsx?$/,
          exclude: /node_modules/,
          loader: 'eslint-loader'
        },
      ]
      // other modules options here
    }
};

注意node_modules文件夹不包括在检查的范围内,所以程序只会检查你实际的组件代码。

webpack将在编译过程结束后把所有的检查结果输出到控制台。

turris.js——汇总一切

结合以上提及的所有内容,我创造了turris.js——它包含一系列helper包,还有一个yeoman生成器,你可以用它轻松地为es6 react应用和独立组件搭建脚手架。

如果你对生成器不感兴趣,只想看看应用和独立组件的示例代码,你可以在它们各自的github仓库中找到它们:还有。

创建新应用

我尝试使创建新应用尽可能地简单,你可以这样创建一个新应用:

  • 确保你已安装最新的io.js和npm;
  • 从npm安装yeoman和turris-generator:

npm install -g yo generator-turris

  • 创建一个新文件夹存放你的app,进入这个文件夹,执行turris生成器:




  • 在回答一系列问题后,yeoman将为你完成所有工作;
  • 执行“npm start”,启动你的新app;
  • 访问http://localhost:8080,打开你最喜欢的编辑器并将应用改为你喜欢的样子。

除了为基础应用搭建脚手架外,turris生成器还提供了三个helper生成器:

1.组件生成器——将在你的app中生成一个新的组件,可以非常便捷地生成你将不会重用的小组件;
2.页面生成器——将生成一个新页面并将它插入到react路由中,这里没有什么奇妙之处,它只是一个帮助你节省时间的子生成器;
3.docker生成器——将生成一个dockfile,其中包含所有运行app所需的文件。
更多有关使用方法、子生成器、项目结构以及其它内容信息,可以在中找到。
创建一个独立组件

创建一个组件并不难,你可以这样做(需求与主生成器相同):

通过npm安装turris-generator-component:
$ npm install -g generator-turris-component  

为你的组件创建一个新文件夹,进入这个文件夹,执行turris组件生成器:



  • 在回答一系列问题后,yeoman将为你完成所有工作;
  • 执行“npm start”,在调试模式下启动你的组件;
  • 访问http://localhost:8080,打开你最喜欢的编辑器并将应用改为你喜欢的样子。

更多有关使用方法、项目结构以及其它内容信息,可以在项目仓库的readme文件中找到。
结束语

希望你已在这篇文章中找到有用的内容,或许你甚至已尝试我编写的生成器。即使你没有这样做——也请帮助我宣传一下!如果你已经尝试过——我非常乐意听取任何反馈意见,处理你们可能遇到的问题。当然,也很欢迎大家提交pull requests。(译者:刘振涛,审校:陈秋歌)

关于作者:tim ermilov,从事移动和web开发工作。

英文原文:
  • 大小: 19.7 kb
  • 大小: 24.2 kb
1
0
评论 共 3 条 请登录后发表评论
3 楼 2016-03-19 11:20
绝对的好文 绝对的好文
2 楼 2015-07-23 10:02
这样的好文没人顶。看来iteye真的有些没落了。
1 楼 2015-05-26 15:53
绝对的好文,我最近也在学

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 这是一个建造webpack react项目脚手架的简易教程,参照了的配置方式。每一个例子都有非常详细的建造步骤。 运行并启动项目 克隆项目到本地以后,选择要运行的示例进入到该项目路径下 安装: npm install 运行: ...

  • react16.5.2 ecmascript 6 和jsx支持 react路由器v4 使用和组件测试 代码覆盖率 启用了范围提升功能的最新webpack(v.4.16.5),babel 7和webpack dev server(v.4.19.1) 使用更换热模块 es6 linting和文件更改时...

  • 无论构建多大,我在构建的每个react项目中都没有使用过其他一致的工具。 babel:即使您只是编写一个快速测试,您也可能希望在组件中使用jsx,而不是react.createelement遍地写出react.createelement 。 we

  • #用webpack构建的简单react应用实践 step by step 安装nodejs npm install 相关插件 npm install webpack -g 全局安装webpack npm install xxx-loader --save-dev 加入相应资源加载工具 执行webpack打包到bundle.js ...

  • 基本react 使用babel构建可测试的react应用程序的最小框架。设计目标使用更少的工具(不要使用yeoman,gulp,bower等) 带webpack和热加载器的babel 6 使用模拟出的dom进行快速测试导入css文件作为类名分开的组件...

  • babel是javascript编译器,能将es6代码转换成es5代码,让我们开发过程中放⼼使⽤js新特性⽽不⽤担⼼兼容性问题。并且还可以通过插件机制根据需求灵活的扩展。 babel在执⾏编译的过程中,会从项⽬根⽬录下的 ....

  • redux-react-babel-webpack 使用webpack es6打包的带有react 0.14的redux immutable devtools react-router的示例实现。 使用护照登录twitter的oatuh示例。 柴摩卡(mocha)的示例测试。 app更是一个尝试新...

  • react,webpack,babel,jest,eslint入门 这是最好的基本电池,包括webpack,babel,react,scss和starter repo。 入门 git clone --depth 1 git@github.com:oscarmorrison/react-webpack-starter.git [new-...

  • #es6 webpack react boilerplate一个如何使用和构建es6和react常见示例的小例子: 用es6语法编写javascript代码 将javascript文件存储在* .es6中 通过babel转换es6> es5 为开发服务器提供热代码重载 提供构建工具...

  • react-douban 仿豆瓣电影app项目a react.js project一个基于react.js仿豆瓣电影项目,使用react-router、webpack、redux等技术, 数据来源 包含左右滑动,上拉加载更多等功能目录§§§§详情可参阅 package....

  • 你得到什么: react用户界面助焊剂体系结构火力基地萨斯webpack构建es6语法(babel)开始吧下载依赖项: npm install通过以下方式启动应用程序: npm start转到计数器小部件功能: 将命名计数器添加到计数器列表中...

  • react播放器一个react django web音频播放器-前端部分react redux sockjs es6 webpack babel安装路线图前1.0版播放清单遮阳板时分双工文献资料风格播放器地位非常阿尔法!

  • react-redux示例此仓库包含两个使用react和redux的示例应用程序,它们是使用babel和webpack构建的,并使用jest进行了测试: (基本,无异步操作) (高级,包含异步操作,路由,身份验证流等) (单击上面的项目链接...

  • 用于创建webpack捆绑的react应用程序的样板(使用es6 ,babel,sass和webpack开发服务器) 产品特点 es6及更高版本=> es5代码转译(使用babel) 用sass样式 使用webpack捆绑文件 使用webpack开发服务器进行本地...

  • ##react样板该项目使用es2018,react,sass,webpack 4和babel 7构建。 用于代码样式指南。 每个主要编辑器都有一个prettier扩展名,可在保存时自动设置样式。 是的webpack管道基于供应商前缀自动追加内使用....

  • 由于您的应用程序始终可以在构建映像中期望的环境中运行,因此测试和部署比以往任何时候都更加简单,因为您的构建将完全可移植并可以在任何环境中按设计运行。 而且,由于容器是轻量级的,并且无需管理程序的额外...

  • npm install babel webpack webpack-dev-server -g npm install npm start 打开浏览器到

  • vb语言vb光盘管理系统设计(源代码 系统)本资源系百度网盘分享地址

  • h型脚架疲劳测试机sw16可编辑_零件图_机械工程图_机械三维3d建模图打包下载.zip

global site tag (gtag.js) - google analytics
网站地图