原来babel 编译jsx不成功能直接编译 JSX.官方用的是哪个

原来Babel 能直接编译 JSX.官方用的是哪个_百度知道
原来Babel 能直接编译 JSX.官方用的是哪个
我有更好的答案
比如.hta 的执行方式看似一个独立的应用程序JavaScript 依赖于浏览器的运行环境,只能以文本的形式被解释执行。有些运行形式.js 。所以。是一种解释执行的脚本语言。其实后台也是解释执行的,不能被编译
其他类似问题
为您推荐:
babel的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁最新react弃用了jsxtransformer了那jsx还能用吗_百度知道
最新react弃用了jsxtransformer了那jsx还能用吗
这个依赖的库改为browser.js页面script标签的type也由text/jsx改为text&#47,浏览器端实现对jsx的编译依赖jsxtransformer.14前.14后.js 在react 0最新react弃用了jsxtransformer了那jsx还能用这个确实是百度就能解决的问题 补充下楼上的回答在react 0
其他类似问题
为您推荐:
react的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Atom编辑器中自动编译jsx文件 - 简书
下载简书移动应用
写了1124字,被2人关注,获得了3个喜欢
Atom编辑器中自动编译jsx文件
Facebook之前有提供jsx工具,可以通过命令行实现jsx文件编译成js文件,babel的强大让facebook放弃了jsxTransform工具,直接用babel来实现jsx到js的编译,不过通过使用babel命令行来进行jsx的编译还是不方便。幸运的是现在atom可以安装language-babel插件来实现jsx的自动编译,jsx编辑时一按保存按钮就会自动生成js文件和sourceMap文件,真是高大上。安装language-babel的过程就不说了,简单说一下配置:(1)在Atom的language-babel的Setting中将Allow Local Override打勾?(2)在你的项目根目录建立一个.languagebabel文件,配置类似如下实例:{“babelTranspilePath”:”./assets/js/app”, //jsx文件编译成js文件的存放目录“babelSourcePath”:”./assets/js/src”, //jsx文件的源目录“transpileOnSave”:true, //在保存时是否自动编译“createMap”:false, //是否创建sourceMap文件,有用sourcemap的可以true“babelMapsAddUrl”:false, //是否在生成的js最下方添加sourceMap的地址“createTargetDirectories”:false, //当生成js文件时,对应的目录不存在,是否自动创建“createTranspiledCode”:true //为true时才会编译}(3)用atom编辑jsx文件时,要注意右下角下图所示这个地方,系统要以Babel ES6 JavaScript方式打开的才会使用到language-babel插件,如果不是,请点击更改。配置完毕后,你可以测试一下,写一个jsx文件,然后按保存,如果正常的话,系统会在右上角弹出对话框,告诉你成功编译了。??
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
@IT 专题 由 IT大分类,转定位于IT·互联网行业观察与思考,数码产品极客体验。
主编:向右奔跑 http://www.ji...
· 85991人关注
生活在程序员圈中,确是伪程序员!
· 306人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:使用 Babel + React + Webpack 搭建 Web 应用 - 推酷
使用 Babel + React + Webpack 搭建 Web 应用
同志们,我又来闲扯前端了。掐指一算不务正业地折腾前端已经有将近一个月的时间了,这段时间零零散散做了三四个简单的小项目,尝试了 Grunt Gulp Webpack 之类的项目构建工具,折腾了 AngularJS ReactJS VueJS 之类的前端框架,对比了 Jade Mustache Ejs 之类的模板引擎,把玩了 Sass Less Stylus 之类的预处理器,还借助着 Babel 体验了一把 ES6+ ,心中一直有这样一种感觉:还是 iOS 好啊!(别问我为什么试这么多东西,挑一个用不就行了吗?是啊,但是不试一遍怎么知道挑哪个好Q_Q
简单整理一下最新的一个项目:一个用于微信传播的 HTML5 小活动,源码在活动上线之后会开源到 Github 上。
Yeoman 在前面的文章中介绍过,是一款脚手架工具。新项目使用的是
这个模板,在
里介绍了一些常用的扩展方案,主要是 gulp 相关的一些配置。
Babel 是一款 JavaScript 转译器,它能够将 ES6+ 的代码转译为主流浏览器支持的 ES5 代码,而且还可以通过插件加载 JSX 的语法。
可以在 Babel 的
里体验一下它的神奇之处。输入一段 ES6 的内容:
var add = (a, b) =& {
console.log('Hello')}add(1, 2)
转换之后的结果是:
'use strict';var add = function add(a, b) {
console.log('Hello');};add(1, 2);
这样就可以无忧无虑的直接使用 ES6+ 开发了 Web 项目了。
Webpack 是一款模块打包工具,在 Webpack 当中,所有的资源都被当作是模块,各种资源通过各种 loader 加载,比如 babel 就提供了
插件,用于在 Webpack 中加载 babel 编译 js 文件。
在项目里用 npm 安装好依赖,添加一个 Webpack 任务,设置 JSX 和 Babel 的相关配置,就可以在项目里使用 React 和 Babel 了:
gulp.task('webpack', cb =& {
entry: './app/scripts/app.jsx',
path: path.resolve(__dirname, '.tmp/scripts/'),
resolve: {
extensions: ['', '.js', '.jsx']
loaders: [{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
presets: ['react', 'es2015', 'stage-0']
}, (err, stats) =& {
if (err) {
throw new gutil.PluginError('webpack', err);
console.log(stats.toString());
React 是 Facebook 开源的一款前端框架,专注于 View 层,提供数据驱动、可组合的视图组件。结合 JSX 语法写出来大概是这个样子的:
var CommentBox = React.createClass({
render: function() {
&div className=&commentBox&&
Hello, world! I am a CommentBox.
}});React.render(
&CommentBox /&,
document.getElementById('content'));
从语法角度来讲,我是不太能接受 React 这种设计的。渲染函数包含了大量业务逻辑,看着像是程序片断而不能直观提供视觉呈现。虽然强调了『模块化』的概念,可以通过封装各种单位模块然后逐渐拼接成完整项目,但是,就是感觉不够优雅。
不过学习的过程中了解了不少有趣的思想,比如单向数据流、Virtual DOM,还有通过 props 和 state 强调『状态管理』,减少可变因素,这些都让我受益匪浅。
React 一般会配合
使用,官方提供了
的例子可以作为入门参考。FLUX 的结构大概是这样的:
看起来很美好,不过只是照着做了边教程,还没在项目里试过,等到后面有项目可以体验一下。
以上内容相当于最近的个人学习小结,匆匆忙忙一笔带过,只是做个记录。
感觉前端是一个很有趣的领域,每个人都在尝试用各种姿势造着各种轮子,接下来的时间不再折腾别人的轮子了,花点时间补补基础知识。
教练,我想写 Swift 。
参考资料:
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致ES2015 & babel 实战:开发NPM模块 - CNode技术社区
积分: 3310
人因梦想而伟大。
原文链接:
近一年来,JavaScript界关于ES6(ECMAScript 6,本文简称ES6)的讨论越来激烈,作为未来要统一全宇宙的语言(PHP是世界上最好的语言,但JavaScript终将统一全宇宙),JavaScript的运行环境众多,对ECMAScript标准的支持程度不一,所以对于ES6我一直处于观望状态。
前不久ES6标准正式发布,而Node.js也在最近刚刚发布了5.1.0版本,对ES6标准的支持也越来越完善,babel(一个将ES6/ES7写的代码转换为ES5代码的编译器)也发布了6.0版本,近期也涌现出了不少好文章(比如写的),种种迹象表明ES6真的要火了,而我也终于按耐不住了……
这几天正在写一个(可以得到下载进度信息),正好可以使用ES6新语法特性来改写,作为我写下的第一个使用ES6语法的NPM模块。本文内容将分为以下几部分:
配置babel编译环境
本文的重点是介绍借助babel开发Node.js项目的基本方法,同时会简略介绍文中出现的ES2015新语法,具体介绍可阅读所著的或babel官方文档中的。
babel官方提供了一个,可以实时输出转换后的JavaScript代码,并且看到其运行结果,对于初学者尤为有用。访问网址http://babeljs.io/repl ,其界面如下:
说明:使用时勾选左边的Experimental可使用最新的语法特性。
由于相关软件和模块正处于高速发展期,无法保证你阅读这篇文章的时候还能照着一步一步准确无误地运行下去,以下列出在编写本文时所用到的软件和模块的版本:
Node.js v5.1.0
npm 3.3.12
babel 6.2.0 (babel-core 6.2.1)
mocha 2.3.4
配置babel编译环境
1、安装babel
Babel is a JavaScript compiler. Use next generation JavaScript, today
目前最新版的Node.js(v5.1.0)还未完全支持ES2015的新语法特性,而且我们编写的模块可能要在Node v0.12.x或更低版本下运行,因此需要借助babel将ES2015标准的JavaScript程序转换成ES5标准的。
执行以下命令安装babel:
$ npm i -g babel-cli
由于babel依赖的模块比较多,可能会花费比较长的时间甚至安装不成功,可以尝试使用cnpmjs的NPM镜像,比如(简单在安装命令末尾添加--registry=http://registry.npm.taobao.org):
$ npm i -g babel-cli --registry=http://registry.npm.taobao.org
镜像的详细介绍可访问其官网:
安装完成后,系统将获得以下两个命令:
babel 编译器
babel-node 可以直接运行ES2015程序的Node命令
babel-cli的详细用法可以参考其文档:
2、初始化项目
执行以下命令初始化项目(执行npm init时需要按提示输入相应信息,可直接按回车跳过):
$ mkdir es2015_demo && cd es2015_demo && git init && npm init
现在我们新建一个文件test.js试试是否能正常运行:
function sleep(ms = 0) {
return new Promise((resolve, reject) =& setTimeout(resolve, ms));
async function test() {
for (let i = 0; i & 10; i++) {
await sleep(500);
console.log(`i=${i}`);
test().then(() =& console.log('done'));
执行以下命令运行test.js:
$ babel-node test.js
在我本机的环境下显示以下错误信息:
/usr/local/lib/node_modules/babel-cli/node_modules/babel-core/lib/transformation/file/index.js:540
SyntaxError: /private/tmp/es2015_demo/test.js: Unexpected token (5:6)
& 5 | async function test() {
for (let i = 0; i & 10; i++) {
await sleep(500);
console.log(`i=${i}`);
由提示信息可判断出,应该是不支持async function导致的,因为这是ES7标准中定义的新语法,需要配置相应的babel插件才能支持它。本文为了方面使用最新的JavaScript语法,暂时不考虑babel的编译性能,直接开启所有可能用到的插件,具体可以自行研究babel的官方文档。
新建文件.babelrc:
&presets&: [&es2015&, &stage-0&]
.babelrc为babel的配置文件,保存在项目的根目录下,其中presets用于设置开启的语法特性集合,详细介绍可参考官方文档: 和
接下来我们还需要安装插件依赖的模块,执行以下命令安装并保存到package.json的devDependencies中:
$ npm i babel-preset-es2015 babel-preset-stage-0 --save-dev
现在再重新执行test.js,可看到控制台每隔500ms打印出一行,直到输出done时结束:
$ babel-node test.js
3、编译程序
在发布项目时,要求可以在不依赖babel编译器的环境下运行,因此我们需要将ES2015的程序编译成ES5的:
$ babel test.js --out-piled.js
执行上面的命令后,生成了编译后的文件<piled.js,我们尝试执行它看看:
$ piled.js
在我的系统环境下提示以下出错信息:
&#x2F;private&#x2F;tmp&#x2F;es2015_demo&#piled.js:4
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
ReferenceError: regeneratorRuntime is not defined
at &#x2F;private&#x2F;tmp&#x2F;es2015_demo&#piled.js:4:31
经阅读官方文档可知,编译后的JavaScript程序有时候需要依赖一些运行时polyfill,通过安装babel-polyfill模块来获得:
$ npm i babel-polyfill --save
然后,我们需要修改编译后的文件<piled.js,在其首行加上以下代码来载入babel-polyfill:
require(&#x27;babel-polyfill&#x27;);
再次执行<piled.js便可看到与$ babel-node test.js一样的结果。
polyfill的详细介绍可参考官方文档:
至此,我们已经配置了一个能使用ES2015语法的Node.js运行环境了。
1、功能描述
本文以模块为例,该模块是一个主要功能是根据一个URL来下载文件到本地,或者本地直接文件的复制,同时提供下载/复制进度信息。其使用方法如下:
let download = require(&#x27;lei-download&#x27;);
let source = &#x27;一个URL或者本地文件名&#x27;;
let target = &#x27;要存储到的本地位置,null|false|undefined表示自动生成一个临时文件&#x27;;
&#x2F;&#x2F; 用于获取进度通知的函数,可以省略
let progress = (size, total) =& console.log(&#96;进度:${size}&#x2F;${total}&#96;);
download(source, target, progress)
.then(filename =& console.log(&#96;已保存到:${filename}&#96;))
.catch(err =& console.log(&#96;出错:${err}&#96;));
&#x2F;&#x2F; 也可以使用callback模式
download(source, target, progress, (err, filename) =& {
if (err) console.log(&#96;出错:${err}&#96;);
else console.log(&#96;已保存到:${filename}&#96;);
在编写模块时,我们首先要实现以下两个函数的功能:
downloadFile(source, target, progress) 从一个URL下载文件并保存到本地
copyFile(source, target, progress) 复制一个本地文件
然后再编写一个download()函数来判断source参数,并选择使用downloadFile()或者copyFile()来完成请求。
2、编写程序
在本项目中,所有的ES2015源程序均保存在src目录下,发布项目时会执行相应的命令将其编译并输出到lib目录,具体方法在**「发布模块」**小节中介绍。
实现copyFile()函数,新建文件src/copy.js:
import fs from &#x27;fs&#x27;;
export default function copyFile(source, target, progress) {
return new Promise((resolve, reject) =& {
fs.stat(source, (err, stats) =& {
if (err) return reject(err);
let ss = fs.createReadStream(source);
let ts = fs.createWriteStream(target);
ss.on(&#x27;error&#x27;, reject);
ts.on(&#x27;error&#x27;, reject);
let copySize = 0;
ss.on(&#x27;data&#x27;, data =& {
copySize += data.
progress && progress(copySize, stats.size);
ss.on(&#x27;end&#x27;, () =& resolve(target));
ss.pipe(ts);
import fs from 'fs'为ES2015模块系统加载模块的方式,可理解为var fs = require('fs'),具体在下文「模块系统」一节中介绍。
通过fs.createReadStream(source)和fs.createWriteStream(target)来创建读取文件流和写入文件流,并监听读取文件流的data事件获得当前进度信息。
export default function copyFile() {}将函数copyFile()作为模块输出,相当于module.exports = function copyFile() {},具体在下文「模块系统」一节中介绍。
函数执行后返回一个Promise对象,通过其.then()和.catch()来获取执行结果,关于Promise的详细介绍可阅读所著的中一章。
为了测试该代码能否正常工作,可在文件末尾增加以下测试程序(在编写单元测试时将删除):
copyFile(__filename, &#x27;&#x2F;tmp&#x2F;copy.js&#x27;, (size, total) =& console.log(&#96;进度${size}&#x2F;${total}&#96;))
.then(filename =& console.log(&#96;已保存到${filename}&#96;))
.catch(err =& console.log(&#96;出错:${err}&#96;));
以上程序的作用是将当前JavaScript文件复制到/tmp/copy.js,使用babel-node执行该文件将得到以下结果:
$ babel-node src&#x2F;copy.js
进度749&#x2F;749
已保存到&#x2F;tmp&#x2F;copy.js
实现downloadFile()函数,新建文件src/download.js:
import fs from &#x27;fs&#x27;;
import request from &#x27;request&#x27;;
export default function downloadFile(url, target, progress) {
return new Promise((resolve, reject) =& {
let s = fs.createWriteStream(target);
s.on(&#x27;error&#x27;, reject);
let totalSize = 0;
let downloadSize = 0;
let req = request
encoding: null
.on(&#x27;response&#x27;, res =& {
if (res.statusCode !== 200) {
return reject(new Error(&#x27;status #&#x27; + res.statusCode));
totalSize = Number(res.headers[&#x27;content-length&#x27;]) ||
res.on(&#x27;data&#x27;, data =& {
downloadSize += data.
progress && progress(downloadSize, totalSize);
res.on(&#x27;end&#x27;, () =& resolve(target));
程序使用request模块来下载URL的内容,使用时执行命令$ npm i request --save安装该模块。
通过request模块的pipe()方法将收到的数据写入到fs.createWriteStream(target)创建的写入文件流中,request模块的详细使用方法可参考其文档:
为了测试该代码能否正常工作,可在文件末尾增加以下测试程序(在编写单元测试时将删除):
let url = &#x27;http:&#x2F;&#x2F;dn-cnodestatic.qbox.me&#x2F;public&#x2F;images&#x2F;cnodejs_light.svg&#x27;;
downloadFile(url, &#x27;&#x2F;tmp&#x2F;avatar.jpg&#x27;, (size, total) =& console.log(&#96;进度${size}&#x2F;${total}&#96;))
.then(filename =& console.log(&#96;已保存到${filename}&#96;))
.catch(err =& console.log(&#96;出错:${err}&#96;));
以上程序的作用是将URL为http://dn-cnodestatic.qbox.me/public/images/cnodejs_light.svg的文件复制到/tmp/avatar.jpg,使用babel-node执行该文件将得到以下结果:
$ babel-node src&#x2F;download.js
进度5944&#x2F;5944
已保存到&#x2F;tmp&#x2F;avatar.jpg
实现download()函数,新建文件src/index.js:
import os from &#x27;os&#x27;;
import path from &#x27;path&#x27;;
import mkdirp from &#x27;mkdirp&#x27;;
import copyFile from &#x27;.&#x2F;copy&#x27;;
import downloadFile from &#x27;.&#x2F;download&#x27;;
export default function download(source, target, progress) {
target = target || randomFilename(download.tmpDir);
progress = progress ||
return new Promise((resolve, reject) =& {
mkdirp(path.dirname(target), err =& {
if (err) return callback(err);
resolve((isURL(source) ? downloadFile : copyFile)
(source, target, progress));
let getTmpDir = os.tmpdir || os.tmpD
function randomString(size = 6, chars = &#x27;abcdefghijklmnopqrstuvwxyz&#x27;) {
let max = chars.length + 1;
let str = &#x27;&#x27;;
while (size & 0) {
str += chars.charAt(Math.floor(Math.random() * max));
function randomFilename(tmpDir = getTmpDir()) {
return path.resolve(tmpDir, randomString(20));
function isURL (url) {
if (url.substr(0, 7) === &#x27;http:&#x2F;&#x2F;&#x27;)
if (url.substr(0, 8) === &#x27;https:&#x2F;&#x2F;&#x27;)
export function noop() { }
import copyFile from './copy'用于载入模块,相当于var copyFile = require('./copy')。
download(...args)函数中的...args相当于var args = Array.prototype.call(arguments);。
程序使用mkdirp模块来创建目标文件的上级目录,使用时执行命令$ npm i mkdirp --save安装该模块。
getTmpDir()函数用于取得当前系统的临时目录,通过os.tmpDir()获得。
randomString(size)函数用于生成指定长度的随机字符串。
randomFilename(tmpDir)用于生成临时文件名,默认存储在系统临时目录下,可通过tmpDir参数指定。
isURL(url)函数用于判断参数是否为一个URL。
为了验证程序是否正确,我们可以将上文的src/copy.js和src/download.js中的测试程序放到src/index.js文件的末尾并执行(需要将旧的程序程序删除),比如:
download(__filename, &#x27;&#x2F;tmp&#x2F;copy.js&#x27;, (size, total) =& console.log(&#96;进度${size}&#x2F;${total}&#96;))
.then(filename =& console.log(&#96;已保存到${filename}&#96;))
.catch(err =& console.log(&#96;出错:${err}&#96;));
正常情况下,其执行结果应该跟上文中的结果是一致的。
3、模块系统
Node.js使用的是CommonJS模块系统,模块的输出我们一般通过给exports对象设置属性来做:
&#x2F;&#x2F; 输出变量或函数
exports.x = 123;
exports.y = function () {
console.log(&#x27;hello&#x27;);
可以通过以下方式来操作:
var mod = require(&#x27;.&#x2F;my_module&#x27;);
console.log(mod.x);
也可以通过覆盖module.exports来输出一个函数或者其他数据类型:
module.exports = function () {
console.log(&#x27;hello&#x27;);
通过以下方式来操作:
var fn = require(&#x27;.&#x2F;my_module&#x27;);
而在ES2015中,模块通过export语句来输出:
&#x2F;&#x2F; 普通输出,相当于 exports.x =
export const a = 123;
export var b = 456;
export function c() { }
export class d { }
&#x2F;&#x2F; 默认输出,相当于 module.exports =
export default function y() { }
通过import语句来引入模块,不同的引入方式其含义是不一样的,比如:
&#x2F;&#x2F; 操作 export var x = y 方式的输出
import {a, b, c, d} from &#x27;.&#x2F;my_module&#x27;;
&#x2F;&#x2F; 通过相应的变量名称 a, b, c, d 来操作
&#x2F;&#x2F; 或者将所有输出指向一个对象
import * as mod from &#x27;.&#x2F;my_module&#x27;;
&#x2F;&#x2F; 通过 mod.a, mod.b, mod.c, mod.d 来操作
&#x2F;&#x2F; 操作 export default x 方式的输出
import y from &#x27;.&#x2F;my_module&#x27;;
对于非ES2015程序输出的模块,import * as mod和import mod其结果是一样的,比如:
import * as fs1 from &#x27;fs&#x27;;
import fs2 from &#x27;fs&#x27;;
&#x2F;&#x2F; fs1.readFile() 和 fs2.readFile() 是一样的
为了更容易理解ES2015的模块系统原理,我们可以通过阅读编译后的JavaScript程序来了解。访问或将程序保存到本地,并执行babel file.js来查看编译后的程序。
以下ES2015代码:
export const a = 123;
export var b = 456;
export function c() { }
export class d { }
export default function y() { }
编译后结果如下:
&use strict&;
Object.defineProperty(exports, &__esModule&, {
value: true
exports.c =
exports[&default&] =
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError(&Cannot call a class as a function&);
var a = 123;
exports.a =
var b = 456;
exports.b =
function c() {}
var d = function d() {
_classCallCheck(this, d);
exports.d =
function y() {}
由上面的代码可以看出,export var b = 456这样的输出方式,实际上相当于var b = exports.b = 456,即直接设置exports对象的属性来完成。而export default y则是设置exports对象的default属性。
另外,还设置了exports.__esModule = true来标记这是一个ES2015输出的模块,在通过import来引入模块时会判断此属性来执行相应的规则,下文将详细介绍。
再看看以下的ES2015代码:
import {a, b, c, d} from &#x27;.&#x2F;my_module&#x27;;
import * as mod from &#x27;.&#x2F;my_module&#x27;;
import y from &#x27;.&#x2F;my_module&#x27;;
其编译后的JavaScript代码如下:
&#x27;use strict&#x27;;
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
&#x27;default&#x27;: obj
function _interopRequireWildcard(obj) {
if (obj && obj.__esModule) {
var newObj = {};
if (obj != null) {
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
newObj[&#x27;default&#x27;] =
return newO
var _my_module = require(&#x27;.&#x2F;my_module&#x27;);
var mod = _interopRequireWildcard(_my_module);
var _my_module2 = _interopRequireDefault(_my_module);
_my_module.a;
_my_module2[&#x27;default&#x27;];
首先,a是通过import {a} from './my_module'来引入的,编译后的代码中访问a使用的是_my_module.a,而_my_module = require('./my_module'),所以其对应的是export var a = 123这样的输出。
mod是通过import * as mod from './my_module'来引入的,其编译后的代码为_interopRequireWildcard(require('./my_module'))。在_interopRequireWildcard()函数中,如果载入的模块是由ES2015输出的,那么不做任何处理,否则会生成一个输入模块的拷贝,并且设置其default属性为自身。
y是通过import y from './my_module'来引入的,对y的访问被编译成了_my_module2['default'],所以y实际上是export default的输出。而_my_module2 = _interopRequireDefault(require('./my_module')),函数_interopRequireDefault()对载入的非ES2015模块做了处理,会返回一个default属性指向该模块的新对象。
当然模块系统的还有更复杂的语法规则,详细说明可参考:所著的中一章。
4、封装模块
上文例子中的download()函数所在的文件src/index.js中用到randomFilename()和isURL()这两个函数,为了使得代码结构更清晰,我们尝试把这些工具函数转移到src/utils.js中。
新建文件src/utils.js:
import path from &#x27;path&#x27;;
import os from &#x27;os&#x27;;
let getTmpDir = os.tmpdir || os.tmpD
function randomString(size = 6, chars = &#x27;abcdefghijklmnopqrstuvwxyz&#x27;) {
let max = chars.length + 1;
let str = &#x27;&#x27;;
while (size & 0) {
str += chars.charAt(Math.floor(Math.random() * max));
export function randomFilename(tmpDir = getTmpDir()) {
return path.resolve(tmpDir, randomString(20));
export function isURL (url) {
if (url.substr(0, 7) === &#x27;http:&#x2F;&#x2F;&#x27;)
if (url.substr(0, 8) === &#x27;https:&#x2F;&#x2F;&#x27;)
export function noop() { }
说明:getTmpDir()和randomString()仅在函数randomFilename()函数中用到,所以不需要使用export输出。
修改文件src/index.js,将相应的代码删掉,并在文件首部import语句后面增加以下代码:
import {randomFilename, isURL, noop} from &#x27;.&#x2F;utils&#x27;;
本文将以mocha测试框架为例,单元测试程序也将使用ES2015来写。
首先执行以下命令安装mocha:
$ npm i -g mocha
安装完成后可执行以下命令验证是否安装成功:
$ mocha --version
通过阅读babel的官方文档(访问http://babeljs.io/docs/setup/#mocha )可知,为了让Node.js中的require()函数能直接载入ES2015程序,需要依赖babel-core模块,执行以下命令安装:
$ npm i babel-core mocha --save-dev
运行mocha命令的时候,需要增加额外的参数--compilers js:babel-core/register让其使用babel来载入JavaScript程序。为了方便,我们可以修改package.json文件,增加以下内容:
&scripts&: {
&test&: &mocha --compilers js:babel-core&#x2F;register&
说明:我们通过npm init命令生成package.json文件时,已经自动生成了test命令,其默认值为echo \&Error: no test specified\& && exit 1,直接将其改为mocha --compilers js:babel-core/register即可。
以上准备工作完成后,便可以开始写单元测试程序了。新建文件test/test.js:
import assert from &#x27;assert&#x27;;
import path from &#x27;path&#x27;;
import fs from &#x27;fs&#x27;;
import download from &#x27;..&#x2F;src&#x27;;
import {randomFilename} from &#x27;..&#x2F;src&#x2F;utils&#x27;;
let readFile = f =& fs.readFileSync(f).toString();
let getFileSize = f =& fs.statSync(f).
describe(&#x27;es2015_demo&#x27;, () =& {
it(&#x27;复制本地文件成功&#x27;, done =& {
let source = __
let target = randomFilename();
let onProgress =
download(source, target, (size, total) =& {
onProgress =
assert.equal(size, total);
assert.equal(total, getFileSize(source));
}).then(filename =& {
assert.equal(onProgress, true);
assert.equal(target, filename);
assert.equal(readFile(source), readFile(target));
}).catch(err =& {
说明:本文只为了演示如何配置mocha和编写单元测试程序,所以没有给download()函数编写完整的单元测试,仅编写一个测试用例作为演示。
好了,现在执行$ npm test命令看看:
$ npm test
& es2015_demo@1.0.0 test &#x2F;private&#x2F;tmp&#x2F;es2015_demo
& mocha --compilers js:babel-core&#x2F;register
es2015_demo
? 复制本地文件成功
1 passing (51ms)
至此,我们已经完成了使用ES2015编写模块,并使用mocha来进行单元测试,下文将介绍如何通过babel编译程序,并发布模块。
上文已提到,为了让使用ES2015编写的代码能在Node.js上正常运行,需要先将其编译成ES5标准的代码,然后还需要在程序入口载入babel-polyfill模块。
我们可以修改文件package.json,为其增加compile命令:
&scripts&: {
&compile&: &babel -d lib&#x2F; src&#x2F;&
说明:$ babel -d lib/ src/命令表示lib目录下的所有文件,并保存到src目录下。
配置完成后,可以执行$ npm run compile命令编译试试:
$ npm run compile
& @isnc&#x2F;es2015_demo@1.0.0 compile &#x2F;Users&#x2F;glen&#x2F;work&#x2F;tmp&#x2F;es2015_demo
& babel -d lib&#x2F; src&#x2F;
src&#x2F;copy.js -& lib&#x2F;copy.js
src&#x2F;download.js -& lib&#x2F;download.js
src&#x2F;index.js -& lib&#x2F;index.js
src&#x2F;utils.js -& lib&#x2F;utils.js
此时,我们还不能直接载入lib/index.js文件,因为在此之前需要载入babel-polyfill模块。编辑文件package.json,设置模块入口文件:
&main&: &index.js&
说明:使用$ npm init生成package.json文件时,main的默认值即为index.js,可无需修改。
新建文件index.js:
require(&#x27;babel-polyfill&#x27;);
module.exports = require(&#x27;.&#x2F;lib&#x27;).
说明:在src/index.js中download()函数使用的是export default输出,所以在Node.js中需要读取模块输出的default属性。
上文中我们的测试程序是直接载入src目录下的程序,但模块最终发布的却是编译后的程序,为了避免因babel的Bug而导致编译后的程序与源程序功能有差异,我们的单元测试需要改用编译后的代码。
编辑文件test/test.js,将引入src目录的模块:
import download from &#x27;..&#x2F;src&#x27;;
import {randomFilename} from &#x27;..&#x2F;src&#x2F;utils&#x27;;
import download from &#x27;..&#x2F;&#x27;;
import {randomFilename} from &#x27;..&#x2F;lib&#x2F;utils&#x27;;
在编辑package.json文件,将test命令改为先执行compile编译代码后再执行mocha测试:
&scripts&: {
&test&: &npm run compile && mocha --compilers js:babel-core&#x2F;register&
重新执行$ npm test可看到如下结果:
$ npm test
& es2015_demo@1.0.0 test &#x2F;private&#x2F;tmp&#x2F;es2015_demo
& npm run compile && mocha --compilers js:babel-core&#x2F;register
& es2015_demo@1.0.0 compile &#x2F;private&#x2F;tmp&#x2F;es2015_demo
& babel -d lib&#x2F; src&#x2F;
src&#x2F;copy.js -& lib&#x2F;copy.js
src&#x2F;download.js -& lib&#x2F;download.js
src&#x2F;index.js -& lib&#x2F;index.js
src&#x2F;utils.js -& lib&#x2F;utils.js
es2015_demo
? 复制本地文件成功
1 passing (42ms)
在开发项目时,一般都会使用Git这样的源代码版本管理工具。上文例子中,lib目录的文件是编译生成的,可以不需要纳入到版本管理中。Node.js项目在安装模块时会将其保存到node_modules目录下,这些内容也是不应该纳入版本管理的。可以添加文件.gitignore来将其排除:
node_modules
如果要将模块发布到NPM上,ES2015编写的源程序也是不需要的,可以添加文件.npmignore来将其排除:
在使用$ npm publish命令发布模块时,可以设置prepublish命令来让其自动执行编译。编辑文件package.json,增加以下内容:
&scripts&: {
&prepublish&: &npm run compile&
现在我们执行$ npm publish就可以发布模块了:
$ npm publish
& @leizongmin&#x2F;es2015_demo@1.0.0 prepublish &#x2F;Users&#x2F;glen&#x2F;work&#x2F;tmp&#x2F;es2015_demo
& npm run compile
& @leizongmin&#x2F;es2015_demo@1.0.0 compile &#x2F;Users&#x2F;glen&#x2F;work&#x2F;tmp&#x2F;es2015_demo
& babel -d lib&#x2F; src&#x2F;
src&#x2F;copy.js -& lib&#x2F;copy.js
src&#x2F;download.js -& lib&#x2F;download.js
src&#x2F;index.js -& lib&#x2F;index.js
src&#x2F;utils.js -& lib&#x2F;utils.js
+ @leizongmin&#x2F;es2015_demo@1.0.0
上文例子中需要依赖mocha和babel两个工具,当我们开发多个项目或将其作为开源项目发布出去时,可能不同的项目所依赖babel的版本是不一样的,为了开发环境一致,一般我们需要在当前项目中执行其开发时所指定的babel版本。
首先执行以下命令安装babel-cli和mocha:
$ npm i babel-cli mocha --save-dev
安装完成后,对于上文中使用的babel和mocha命令,可以使用./node_modules/.bin/babel和./node_modules/.bin/mocha来执行。编辑package.json文件,更改compile和test命令:
&scripts&: {
&compile&: &.&#x2F;node_modules&#x2F;.bin&#x2F;babel -d lib&#x2F; src&#x2F;&,
&test&: &npm run compile && .&#x2F;node_modules&#x2F;.bin&#x2F;mocha --compilers js:babel-core&#x2F;register&
本文示例模块输出的download()函数使用的是Promise的异步模式,对于习惯使用callback模式的用户,我们也可以通过简单的修改来使其支持callback模式。
编辑文件src/utils.js,增加callbackify()函数:
export function callbackify(fn) {
let argc = fn.
return (...args) =& {
let callback = args[argc];
if (typeof callback !== &#x27;function&#x27;) callback =
return fn(...args)
.then(ret =& {
callback && callback(null, ret);
return Promise.resolve(ret);
.catch(err =& {
callback && callback(err);
return Promise.reject(err);
编辑文件src/index.js,将其改为以下内容:
import path from &#x27;path&#x27;;
import mkdirp from &#x27;mkdirp&#x27;;
import copyFile from &#x27;.&#x2F;copy&#x27;;
import downloadFile from &#x27;.&#x2F;download&#x27;;
import {randomFilename, isURL, noop, callbackify} from &#x27;.&#x2F;utils&#x27;;
export default callbackify(function download(source, target, progress) {
target = target || randomFilename(download.tmpDir);
progress = progress ||
return new Promise((resolve, reject) =& {
mkdirp(path.dirname(target), err =& {
if (err) return callback(err);
resolve((isURL(source) ? downloadFile : copyFile)
(source, target, progress));
说明:callbackify()函数的作用是返回一个新的函数,这个函数可以支持原函数的Promise模式,同时支持callback模式。
现在再给test/test.js增加一个测试用例:
it(&#x27;复制本地文件成功 callback&#x27;, done =& {
let source = __
let target = randomFilename();
let onProgress =
download(source, target, (size, total) =& {
onProgress =
assert.equal(size, total);
assert.equal(total, getFileSize(source));
}, (err, filename) =& {
assert.equal(err, null);
assert.equal(onProgress, true);
assert.equal(target, filename);
assert.equal(readFile(source), readFile(target));
如无意外,重新执行$ npm test是可以测试通过的。
本文的初稿在一个星期之前已经完成,一开始看到ES2015的新语法特性时眼前一亮,接着又觉得使用的时候有点繁琐,比如每次运行程序都有先使用babel编译,程序运行出错时定位的位置跟ES2015源码的位置不同等等。后来经过几天的摸索,发觉新的语法特性确实可以少打了很多代码,而且程序的表现力也更强了,与babel编译所耗的那几秒时间相比还是很值得的。
本文的示例代码可通过
只用babel写过前台,gulp自动编译。
node的还没试过,据说不少人被babel6坑过。?
弱弱地问问这个怎样调试?找到对应的编译源代码再自己找回对应的 编译前源代码 一一对着来调试?
目前我是直接在编译后的代码上调试的。接下来打算研究一下有没有更直观的调试方法
东西再好,绕这么大个圈子总给人一种不舒服的感觉,就像angular2.0一样,不加乱七八糟前置插件就跑步起来。
老雷出品,必须顶~学习了
东西的确好先 mark 一下 不过呢 生产环境用不上啊。。。
主要目的是使用ES6的新语法(因为以后必将成为主流),过一段时间就可以用上了
吴老师最近研究啥呢?
大大带我飞 ^_^
js神明,一统千秋。
为什么我的babel编译之后不需要babel-polyfill呢?
是否需要babel-polyfill与你使用到的ES6/ES7特性有关,可能有些你暂时没用到,不载入babel-polyfill也不会出错
但是我的代码里出现了很多辅助性质的函数,我在使用browserify的时候,每个打包的文件里都会有这么一个函数,觉得不舒服。。。有没有什么办法可以避免这个问题
好文。。mark
好文!楼主我要给你生猴子? ?
自豪地采用
??(?3?)来来来,生一群猴子
用 typescript 来写 async await 与用babel 有什么区别?
没用过typescript,不清楚,理论上是没多大区别的
不能编译到ES5,只能编译到ES6。
因为只能编译到ES6,所以编译的结果有明显不同
你觉得编译到5好还是6好呢?
请问对于使用babel的node项目,如何调试?调试编译后的代码会不会很麻烦?
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的}

我要回帖

更多关于 babel编译jsx 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信