Browserify + Gulp + Babelify

一看就懂的 React 开发环境建置与 Webpack 入门教学

在进入第二种方法前,首先先介绍一下会用到 BrowserifyGulpBabelify 三种前端开发常会用到的工具:

Browserify

  • 如同官网上说明的:Browserify lets you require('modules') in the browser by bundling up all of your dependencies.,Browserify 是一个可以让你在浏览器端也能使用像 Node 用的 CommonJS 规范一样,用输出(export)和引用(require)来管理模组。此外,也能使用许多在 NPM 中的模组

Gulp

  • Gulp 是一个前端任务工具自动化管理工具。随着前端工程的发展(Task Runner),我们在开发前端应用程式时有许多工作是必须重复进行,例如:打包文件、uglify、将 LESS 转译成一般的 CSS 的档案,转译 ES6 语法等工作。若是使用一般手动的方式,往往会造成效率的低下,所以透过像是 Grunt、Gulp 这类的 Task Runner 不但可以提升效率,也可以更方便管理这些任务。由于 Gulp 是透过 pipeline 方式来处理档案,在使用上比起 Grunt 的方式直观许多,所以这边我们主要讨论的是 Gulp

Babelify

  • Babelify 是一个使用 Browserify 进行 Babel 转换的外挂,你可以想成是一个翻译机,可以将 React 中的 JSXES6 语法转成浏览器相容的 ES5 语法

初步了解了三种工具的概念后,接下来我们就开始我们的环境设置:

  1. 若是电脑中尚未安装 Node(Node.js 是一个开放原始码、跨平台的、可用于伺服器端和网路应用的 Google V8 引擎执行执行环境)和 NPM(Node 套件管理器 Node Package Manager。是一个以 JavaScript 编写的软件套件管理系统,预设环境为 Node.js,从 Node.js 0.6.3 版本开始,npm 被自动附带在安装包中)的话,请先 上官网安装

  2. npm 安装 browserify

  3. npm 安装 gulpgulp-concatgulp-html-replacegulp-streamifygulp-uglifywatchifyvinyl-source-stream 开发环境用的套件(development dependencies)

    1. // 使用 npm install --save-dev 会将安装的套件名称和版本存放到 package.json 的 devDependencies 栏位中
    2. $ npm install --save-dev gulp gulp-concat gulp-html-replace gulp-streamify gulp-uglify watchify vinyl-source-stream
  4. 安装 babelifybabel-preset-es2015babel-preset-react,转译 ES6JSX 开发环境用的套件,并于根目录底下设定 .babelrc,设定转译规则(presets:es2015、react)和使用的外挂

    1. // 使用 npm install --save-dev 会将安装的套件名称和版本存放到 package.json 的 devDependencies 栏位中
    2. $ npm install --save-dev babelify babel-preset-es2015 babel-preset-react
    1. // filename: .babelrc
    2. {
    3. "presets": [
    4. "es2015",
    5. "react",
    6. ],
    7. "plugins": []
    8. }
  5. 安装 react 和 react-dom

    1. $ npm install --save react react-dom
  6. 撰写 Component

    1. // filename: ./app/index.js
    2. import React from 'react';
    3. import ReactDOM from 'react-dom';
    4. class App extends React.Component {
    5. constructor(props) {
    6. super(props);
    7. this.state = {
    8. };
    9. }
    10. render() {
    11. return (
    12. <div>
    13. <h1>Hello, World!</h1>
    14. </div>
    15. );
    16. }
    17. }
    18. ReactDOM.render(<App />, document.getElementById('app'));
    1. <!-- filename: ./index.html -->
    2. <!DOCTYPE html>
    3. <html lang="en">
    4. <head>
    5. <meta charset="UTF-8">
    6. <title>Hello React!</title>
    7. </head>
    8. <body>
    9. <div id="app"></div>
    10. <!-- build:js -->
    11. <script src="./dist/src/bundle.js"></script>
    12. <!-- endbuild -->
    13. </body>
    14. </html>
  7. 设定 gulpfile.js

    1. // filename: gulpfile.js
    2. // 引入所有需要的档案
    3. const gulp = require('gulp');
    4. const uglify = require('gulp-uglify');
    5. const htmlreplace = require('gulp-html-replace');
    6. const source = require('vinyl-source-stream');
    7. const browserify = require('browserify');
    8. const watchify = require('watchify');
    9. const babel = require('babelify');
    10. const streamify = require('gulp-streamify');
    11. // 档案位置参数
    12. const path = {
    13. HTML: 'index.html',
    14. MINIFIED_OUT: 'bundle.min.js',
    15. OUT: 'bundle.js',
    16. DEST: 'dist',
    17. DEST_BUILD: 'dist/build',
    18. DEST_SRC: 'dist/src',
    19. ENTRY_POINT: './app/index.js'
    20. };
    21. // 复制 html 到 dist 资料夹中
    22. gulp.task('copy', function(){
    23. gulp.src(path.HTML)
    24. .pipe(gulp.dest(path.DEST));
    25. });
    26. // 监听档案是否有变化,若有变化则重新编译一次
    27. gulp.task('watch', function() {
    28. gulp.watch(path.HTML, ['copy']);
    29. var watcher = watchify(browserify({
    30. entries: [path.ENTRY_POINT],
    31. transform: [babel],
    32. debug: true,
    33. }));
    34. return watcher.on('update', function () {
    35. watcher.bundle()
    36. .pipe(source(path.OUT))
    37. .pipe(gulp.dest(path.DEST_SRC))
    38. console.log('Updated');
    39. })
    40. .bundle()
    41. .pipe(source(path.OUT))
    42. .pipe(gulp.dest(path.DEST_SRC));
    43. });
    44. // 执行 build production 的流程(包括 uglify、转译等)
    45. gulp.task('copy', function(){
    46. browserify({
    47. entries: [path.ENTRY_POINT],
    48. transform: [babel],
    49. })
    50. .bundle()
    51. .pipe(source(path.MINIFIED_OUT))
    52. .pipe(streamify(uglify(path.MINIFIED_OUT)))
    53. .pipe(gulp.dest(path.DEST_BUILD));
    54. });
    55. // 将 script 引用换成 production 的档案
    56. gulp.task('replaceHTML', function(){
    57. gulp.src(path.HTML)
    58. .pipe(htmlreplace({
    59. 'js': 'build/' + path.MINIFIED_OUT
    60. }))
    61. .pipe(gulp.dest(path.DEST));
    62. });
    63. // 设定 NODE_ENV 为 production
    64. gulp.task('apply-prod-environment', function() {
    65. process.env.NODE_ENV = 'production';
    66. });
    67. // 若直接执行 gulp 会执行 gulp default 的任务:watch、copy。若跑 gulp production,则会执行 build、replaceHTML、apply-prod-environment
    68. gulp.task('production', ['build', 'replaceHTML', 'apply-prod-environment']);
    69. gulp.task('default', ['watch', 'copy']);
  8. 成果展示
    到目前为止我们的资料夹的结构应该会是这样:

    一看就懂的 React 开发环境建置与 Webpack 入门教学

    接下来我们透过在终端机(terminal)下 gulp 指令来处理我们设定好的任务:

    1. // 当只有输入 gulp 没有输入任务名称时,gulp 会自动执行 default 的任务,我们这边会执行 `watch` 和 `copy` 的任务,前者会监听 `./app/index.js` 是否有改变,有的话则更新。后者则是会把 `index.html` 复制到 `./dist/index.html`
    2. $ gulp

    当执行完 gulp 后,我们可以发现多了一个 dist 资料夹

    一看就懂的 React 开发环境建置与 Webpack 入门教学

    如果我们是要进行 production 的应用程式开发的话,我们可以执行:

    1. // 当输入 gulp production 时,gulp 会执行 production 的任务,我们这边会执行 `replaceHTML`、`build` 和 `apply-prod-environment` 的任务,`build` 任务会进行转译和 `uglify`。`replaceHTML` 会取代 `index.html` 注解中的 `<script>` 引入档案,变成引入压缩和 `uglify` 后的 `./dist/build/bundle.min.js`。`apply-prod-environment` 则是会更改 `NODE_ENV` 变数,让环境设定改为 `production`,有兴趣的读者可以参考[React 官网说明](https://facebook.github.io/react/downloads.html)
    2. $ gulp production

    此时我们可以在浏览器上打开我们的 ./dist/hello.html,就可以看到 Hello, world! 了!

(image via srinisoundarsitepointkeyholesoftwaresurvivejs)

| 回首页 |

| 勘误、提问或许愿 |