如何在NodeJS项目中优雅的使用ES6

ace110112 3年前
   <h2>如何在NodeJS项目中优雅的使用ES6</h2>    <p>NodeJs最近的版本都开始支持ES6(ES2015)的新特性了,设置已经支持了async/await这样的更高级的特性。只是在使用的时候需要在node后面加上参数: --harmony 。但是,即使如此node也还是没有支持全部的ES6特性。所以这个时候就需要用到 Babel 了。</p>    <h3>现在开始Babel</h3>    <p>在开始使用Babel之前,假设</p>    <ol>     <li> <p>你已经安装了nodejs,并且已经熟悉了Js。</p> </li>     <li> <p>你也可以使用 <em>npm</em> 安装各种依赖包。</p> </li>     <li> <p>而且你也对ES6(后来改为ES2015)有一定程度的熟悉。</p> </li>    </ol>    <p>同时假设你已经安装了 <strong>yarn</strong> ,并且也熟悉了yarn。Yarn最大的优点就是它比 <em>npm</em> 要快很多,因为yarn只把需要的库下载一次,之后用到的时候直接使用本地缓存的版本。npm每次都会下载这些库。这简直就是浪费生命。如果你还没有安装yarn,也没有关系,下面也会有npm的使用方法。</p>    <p>接下来开始安装配置Babel。安装babel-cli</p>    <pre>  <code class="language-javascript">yarn add babel-cli --dev   // npm install --save-dev babel-cli</code></pre>    <p>安装babel的presets。</p>    <pre>  <code class="language-javascript">yarn add babel-preset-es2015 --dev    // npm install --save-dev babel-preset-es2015</code></pre>    <p>这个时候你就可以使用ES2015的特性了。但是,这还不够,比如我不想用 Promise 我想用更加方便的 async/await 语法。只有es2015这个preset是不够的。</p>    <p>Babel的plugin和preset</p>    <p>Babel本身不处理语言特性的转码。这些功能都是由 <strong>plugin</strong> 和 <strong>preset</strong> 实现的(preset也是一个plugin的集合)。如上文所述,要使用es2015的内容就需要安装 <em>babel-preset-es2015</em> 这个preset。要使用async/await那么就需要安装对应的preset或者插件。为了简单我们安装preset: babel-preset-stage-0 。preset <em>stage-0</em> 包含了async/await相关的插件: <em>babel-plugin-syntax-async-functions</em> 、 <em>babel-plugin-transform-regenerator</em> 。</p>    <pre>  <code class="language-javascript">yarn add babel-preset-stage-0 --dev // npm install --save-dev babel-preset-stage-0</code></pre>    <p>这样还是不能在项目中使用es7的async/await了。还需要更多的配置,有两种方法可以达到目的:</p>    <ol>     <li> <p>使用 babel-polyfill 。有一个不好地地方, babel-polyfill 会污染global对象,所以不适合于library之类的使用。仅适合于web app使用。</p> </li>     <li> <p>使用babel运行时转码工具, transform-runtime 插件。使用这个方法正好弥补了上面的方法的不足之处。它是尤其适合于library一类的项目使用。</p> </li>    </ol>    <p>分别介绍这两种方法。</p>    <p>安装 babel-polyfill :</p>    <pre>  <code class="language-javascript">yarn add babel-polyfill --dev // npm install --save-dev babel-polyfill</code></pre>    <p>之后,在你的项目的入口文件的最上方引入 babel-polyfill 。比如我现在有一个Express的Web App,那么的入口文件就是开启这个app的 <em>index.js</em> 文件。在这个文件的最上方引入polyfill, require('babel-polyfill') 。或者你的入口文件已经是ES2015 的写法了,那么就直接import, import 'babel-polyfill' 。</p>    <p>使用 transform-runtime 也非常简单。安装:</p>    <pre>  <code class="language-javascript">yarn add babel-plugin-transform-runtime --dev // npm install --save-dev babel-plugin-transform-runtime</code></pre>    <p>另外还需要安装 babel-runtime :</p>    <pre>  <code class="language-javascript">yarn add babel-runtime  // npm install --save babel-runtime</code></pre>    <p>之后在 <em>.babelrc</em> 文件中添加如下的配置,两个二选其一即可:</p>    <pre>  <code class="language-javascript">// without options  {    "plugins": ["transform-runtime"]  }    // with options  {    "plugins": [      ["transform-runtime", {        "helpers": false, // defaults to true        "polyfill": false, // defaults to true        "regenerator": true, // defaults to true        "moduleName": "babel-runtime" // defaults to "babel-runtime"      }]    ]  }</code></pre>    <p>剩下的就是欢畅的使用 <em>async/await</em> 了。</p>    <p>另外如果要使用 Object.assing 这样的方法的话,也可以使用插件: babel-plugin-transform-object-assign ,如果要使用解构赋值可以使用插件: babel-plugin-transform-object-rest-spread 。当然这些都包含在了 <em>stage-0</em> 这个preset中。</p>    <p>现在就开始写ES2015的代码吧。在项目中安装ExpressJs,创建一个 <em>index.js</em> 文件。我们来试着创建一个小小的web app作为练习:</p>    <pre>  <code class="language-javascript">import Express from 'express'    let app = Express()    app.get('/', (req, res) => {    res.send('hello world')  })    app.listen(8080, () => console.log('server is running at http://localhost:8080'))</code></pre>    <p>运行命令:</p>    <pre>  <code class="language-javascript">./node_modules/.bin/babel-node index.js --preset es2015, stage-0</code></pre>    <p>使用命令 <em>babel-node</em> *就可以让代码运行起来,后面的参数指定了在转义js代码的时候使用的preset和plugin。</p>    <p>Babel官方推荐的方法是时候用 <em>.babelrc</em> 文件,这一方式可以更加灵活。在项目的更目录上创建 <em>.babelrc</em> 文件,在里面添加你安装的preset和plugin的描述:</p>    <pre>  <code class="language-javascript">{      "presets": ["es2015", "stage-0"]  }</code></pre>    <p>这样可以直接使用 <em>babel-node</em> 来执行代码,或者使用命令 <em>babel</em> 来转义代码。如:</p>    <pre>  <code class="language-javascript">babel -w code/ -d build/</code></pre>    <p>babel命令会从配置文件中读取配置,来变异 <em>code/</em> 目录下的文件,并把转义之后的JavaScript文件导出到 <em>build/</em> 目录下。还有命令行里的参数 <em>-w</em> ,这个命令参数指定的是 <strong>watch</strong> ,每次code目录的文件修改后都会触发babel命令的再次执行。</p>    <p>在文件中使用Source Maps</p>    <p>上面看起来很不错了。但是还有一个问题,在你调试代码的时候,你调试的实际是 <strong>babel</strong> 命令转码之后的js,不是原来你编写的源代码所在的文件。调试的不是源文件,多少会有些不便。比如下面的文件会抛出一个异常:</p>    <pre>  <code class="language-javascript">async function errorAsyncFunc() {    try{      throw new Error('Async function error')    } catch(e) {      throw e    }  }    errorAsyncFunc()</code></pre>    <p>在转码命令中加一个 --source-maps 可以解决这个问题:</p>    <pre>  <code class="language-javascript">babel code/ -d build/ --source-maps</code></pre>    <p>最后在 <em>package.json</em> 里添加scripts节点:</p>    <pre>  <code class="language-javascript">"scripts": {    "build": "babel src -d build --source-maps",    "start": "node build/index.js"  },</code></pre>    <p>接下来:</p>    <pre>  <code class="language-javascript">npm run build</code></pre>    <p>// to be continued...</p>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000008162239</p>    <p> </p>