Webpack 和 React 小書

Webpack 和 React 小書

全文地址
Gitbook 英文原版javascript

這本小書的目的是引導你進入 React 和 Webpack 的世界。他們兩個都是很是有用的技術,若是同時使用他們,前端開發會更加有趣。css

這本小書會提供全部相關的技能。若是你只是對 React 感興趣,那能夠跳過 Webpack 相關的內容,反之亦然。 若是想學習更多的相關知識能夠移步 SurviveJS - Webpack and Reacthtml

React

React 是一個可以讓開發模塊變成簡單的庫。一旦你理解他的工做原理,那你就能夠用它搭建本身的程序,這是不一樣相似 Angular 那種試着包攬一切的框架不一樣的地方。前端

若是你想很快過一遍 React 的知識點,那麼 React 官方教程 是一個很好的開始。java

可能 React 最有趣的事是它一直會嘗試調整傳統的 web 組件的思路。它讓咱們從新思考關注點的分離。它(React Native)也會影響 App 開發。 React Native 提供了一種使用 Javascript 開發原生應用同時保證了原生性能。node

Webpack

Webpack 很是容易操做,它是一個模塊合併的工具,本質就是一個可以把各類組件(HTML,CSS,JS)構建成項目。最方便的是你只須要初始化配置一次,Webpack 會替你作那些繁瑣的事情,同時也保證了讓你能夠在項目中混合使用各類技術而不頭疼。react

若是你在 Webpack 方面徹底是新手的,但想開始一個簡單的教程的話,能夠去 Pete Hunt's guide。你能夠在那裏學習到一些基礎的使用,這裏只是那邊的一個補充。webpack

介紹 Webpack

在 Web 開發歷程上,咱們構建了不少小型的技術解決方案,好比用 HTML 去描述頁面結構,CSS 去描述頁面樣式,Javascript 去描述頁面邏輯,或者你也能夠用一些好比 Jade 去取代 HTML,用 Sass 或 Less 去取代CSS,用 CoffeeScript 或者 TypeScript 之類的去取代 Javascript,不過項目中的依賴多是一件比較煩惱的事情。(須要安裝額外不少的庫)git

這裏有不少爲何咱們須要嘗試那些新技術的理由。無論咱們用什麼,總之,咱們仍是但願使用那些可以處理在瀏覽器端的方案,因此出來了編譯方案。歷史上已經有不少分享了,好比 Make 多是不少解決方案中最知名且是可行的方案。GruntGulp 是在是前端的世界中最流行的解決方案,他們兩個都有不少很是有用的插件。NPM(Node.js 的包管理器)則包含了他們兩個。github

Grunt

Grunt 是相比後面幾個更早的項目,他依賴於各類插件的配置。這是一個很好的解決方案,可是請相信我,你不會想看到一個 300 行的 Gruntfile。若是你好奇 Grunt 的配置會如何,那麼這裏是有個從 Grunt 文檔 的例子:

javascriptmodule.exports = function(grunt) {

  grunt.initConfig({
    jshint: {
      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
      options: {
        globals: {
          jQuery: true
        }
      }
    },
    watch: {
      files: ['<%= jshint.files %>'],
      tasks: ['jshint']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['jshint']);

};

Gulp

Gulp 提供了一個不同的解決方案,而不是依賴於各類插件的配置。Gulp 使用了一個文件流的概念。若是你熟悉 Unix,那麼 Gulp 對你來講會差很少,Gulp 會提供你一些簡單化的操做。在這個解決方案中,是去匹配一些文件而後操做(就是說和 JavaScript 相反)而後輸出結果(好比輸出在你設置的編譯路徑等)。這裏有一個簡單的 Gulpfile 的例子:

javascriptvar gulp = require('gulp');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var del = require('del');

var paths = {
  scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee'],
};

// 不是全部的任務須要使用 streams
// 一個 gulpfile 只是另外一個node的程序,因此你可使用全部 npm 的包
gulp.task('clean', function(cb) {
  // 你能夠用 `gulp.src` 來使用多重通配符模式
  del(['build'], cb);
});

gulp.task('scripts', ['clean'], function() {
  // 壓縮和複製全部 JavaScript (除了第三方庫)
  // 加上 sourcemaps
  return gulp.src(paths.scripts)
    .pipe(sourcemaps.init())
      .pipe(coffee())
      .pipe(uglify())
      .pipe(concat('all.min.js'))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('build/js'));
});

// 監聽文件修改
gulp.task('watch', function() {
  gulp.watch(paths.scripts, ['scripts']);
});

// 默認任務(就是你在命令行輸入 `gulp` 時運行)
gulp.task('default', ['watch', 'scripts']);

這些配置都是代碼,因此當你遇到問題也能夠修改,你也可使用已經存在的 Gulp 插件,可是你仍是須要寫一堆模板任務。

Browserify

處理 Javascript 模塊一直是一個大問題,由於這個語言在 ES6 以前沒有這方面的概念。所以咱們仍是停留在90年代,各類解決方案,好比提出了 AMD。在實踐中只使用 CommonJS ( Node.js 所採用的格式)會比較有幫助,而讓工具去處理剩下的事情。它的優點是你能夠發佈到 NPM 上來避免從新發明輪子。

Browserify 解決了這個問題,它提供了一種能夠把模塊集合到一塊兒的方式。你能夠用 Gulp 調用它,此外有不少轉換小工具可讓你更兼容的使用(好比 watchify 提供了一個文件監視器幫助你在開發過程當中更加自動化地把文件合併起來),這樣會省下不少精力。毋庸置疑,必定程度來說,這是一個很好的解決方案。

Webpack

Webpack 擴展了 CommonJs 的 require 的想法,好比你想在 CoffeeScript、Sass、Markdown 或者其餘什麼代碼中 require 你想要的任何代碼的話?那麼 Webpack 正是作這方面的工做。它會經過配置來取出代碼中的依賴,而後把他們經過加載器把代碼兼容地輸出到靜態資源中。這裏是一個 Webpack 官網 上的例子:

javascriptmodule.exports = {
    entry: "./entry.js",
    output: {
        path: __dirname,
        filename: "bundle.js"
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" }
        ]
    }
};

在接下來的章節中咱們會使用 Webpack 來構建項目來展現它的能力。你能夠用其餘工具和 Webpack 一塊兒使用。它不會解決全部事情,只是解決一個打包的難題,不管如何,這是在開發過程當中須要解決的問題。

踏上征途

在開始以前,你須要把你的 Node.js 和 NPM 都更新到最新的版本。訪問 nodejs.org 查看安裝詳情。咱們將會使用 NPM 安裝一些工具。

開始使用 Webpack 很是簡單,我會展現給你看使用它的一個簡單的項目。第一步,爲你的項目新建一個文件夾,而後輸入 npm init,而後填寫相關問題。這樣會爲你建立了 package.json,不用擔憂填錯,你能夠以後修改它。

安裝 Webpack

接下來咱們安裝 Webpack,咱們要把它安裝在本地,而後把它做爲項目依賴保存下來。這樣你能夠在任何地方編譯(服務端編譯之類的)。輸入 npm i wepack --save-dev。若是你想運行它,就輸入 node_modules/.bin/webpack

目錄結構

項目的目錄結構長這樣:

  • /app

    • main.js
    • component.js
  • /build

    • bundle.js (自動建立)
    • index.html
  • package.json
  • webpack.config.js

咱們會使用 Webpack 在咱們的 /app 裏來自動建立 bundle.js 。接下來,咱們來設置 webpack.config.js

設置 Webpack

Webpack 的配置文件長這樣:

webpack.config.js

javascriptvar path = require('path');


module.exports = {
    entry: path.resolve(__dirname, 'app/main.js'),
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'bundle.js',
    },
};

運行你的第一個編譯

如今咱們有了一個最簡單的配置,咱們須要有什麼東西去編譯,讓咱們開始一個經典的 Hello World,設置 /app 像這樣:

app/component.js

javascript'use strict';


module.exports = function () {
    var element = document.createElement('h1');

    element.innerHTML = 'Hello world';

    return element;
};

app/main.js

javascript'use strict';
var component = require('./component.js');


document.body.appendChild(component());

如今在你的命令行運行 webpack,而後你的應用會開始編譯,一個 bundle.js 文件就這樣出如今你的 /build 文件夾下,須要在 build/ 下的 index.html 去啓動項目。

build/index.html

html<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

這個文件能夠用 html-webpack-plugin 來生成。若是你以爲冒險,那就把剩下的工具交給它來作。使用它就只有一個配置的問題。通常來講使用 Webpack 來工做就是這麼個套路。

運行應用

只要雙擊 index.html 或者設置一個 Web 服務指向 build/ 文件夾。

設置 package.json scripts

npm 是一個很是好用的用來編譯的指令,經過 npm 你能夠不用去擔憂項目中使用了什麼技術,你只要調用這個指令就能夠了,只要你在 package.json 中設置 scripts 的值就能夠了。

在這個案例中咱們把編譯步驟放到 npm run build 中是這樣:

  1. npm i webpack --save - 若是你想要把 Webpack 做爲一個項目的開發依賴,就可使用 --save-dev,這樣就很是方便地讓你在開發一個庫的時候,不會依賴工具(但不是個好方法!)。
  2. 把下面的內容添加到 package.json中。
json"scripts": {
    "build": "webpack"
  }

如今你能夠輸入 npm run build 就能夠編譯了。

當項目愈加複雜的時候,這樣的方法會變得愈來愈有效。你能夠把全部複雜的操做隱藏在 scripts 裏面來保證界面的簡潔。

不過潛在的問題是這種方法會致使若是你使用一些特殊的指令的時候只能在 Unix 環境中使用。因此若是你須要考慮一些未知的環境中的話,那麼 gulp-webpack 會是一個好的解決方案。

注意 NPM 會找到 Webpack,npm run 會把他臨時加到 PATH來讓咱們這個神奇的命令工做。

工做流

若是須要一直輸入 npm run build 確實是一件很是無聊的事情,幸運的是,咱們能夠把讓他安靜的運行,讓咱們設置 webpack-dev-server

設置 webpack-dev-server

第一步,輸入 npm i webpack-dev-server --save,此外,咱們須要去調整 package.json scripts 部分去包含這個指令,下面是基本的設置:

package.json

json{
  "scripts": {
    "build": "webpack",
    "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build"
  }
}

當你在命令行裏運行 npm run dev 的時候他會執行 dev 屬性裏的值。這是這些指令的意思:

  1. webpack-dev-server - 在 localhost:8080 創建一個 Web 服務器
  2. --devtool eval - 爲你的代碼建立源地址。當有任何報錯的時候可讓你更加精確地定位到文件和行號
  3. --progress - 顯示合併代碼進度
  4. --colors - Yay,命令行中顯示顏色!
  5. --content-base build - 指向設置的輸出目錄

總的來講,當你運行 npm run dev 的時候,會啓動一個 Web 服務器,而後監聽文件修改,而後自動從新合併你的代碼。真的很是簡潔!

訪問 http://localhost:8080 你會看到效果。

瀏覽器自動刷新

當運行 webpack-dev-server 的時候,它會監聽你的文件修改。當項目從新合併以後,會通知瀏覽器刷新。爲了可以觸發這樣的行爲,你須要把你的 index.html 放到 build/ 文件夾下,而後作這樣的修改:

build/index.html

html<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
  </head>
  <body>
    <script src="http://localhost:8080/webpack-dev-server.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>

咱們須要增長一個腳本當發生改動的時候去自動刷新應用,你須要在配置中增長一個入口點。

javascriptvar path = require('path');


module.exports = {
    entry: ['webpack/hot/dev-server', path.resolve(__dirname, 'app/main.js')],
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'bundle.js',
    },
};

就是這樣!如今你的應用就能夠在文件修改以後自動刷新了。

默認環境

在上面的例子中咱們建立了 index.html 文件來獲取更多的自由和控制。一樣也能夠從 http://localhost:8080/webpack-dev-server/bundle 運行應用。這會觸發一個默認的你不能控制的 index.html ,它一樣會觸發一個容許iFrame中顯示重合並的過程。

引入文件

模塊

Webpack 容許你使用不一樣的模塊類型,可是 「底層」必須使用同一種實現。全部的模塊能夠直接在盒外運行。

ES6 模塊

javascriptimport MyModule from './MyModule.js';

CommonJS

javascriptvar MyModule = require('./MyModule.js');

AMD

javascriptdefine(['./MyModule.js'], function (MyModule) {

});

理解文件路徑

一個模塊須要用它的文件路徑來加載,看一下下面的這個結構:

  • /app

    • /modules
    • MyModule.js
    • main.js (entry point)
    • utils.js

打開 main.js 而後能夠經過下面兩種方式引入 app/modules/MyModule.js

app/main.js

javascript// ES6
import MyModule from './modules/MyModule.js';

// CommonJS
var MyModule = require('./modules/MyModule.js');

最開始的 ./ 是 「相對當前文件路徑」

讓咱們打開 MyModule.js 而後引入 app/utils

app/modules/MyModule.js

javascript// ES6 相對路徑
import utils from './../utils.js';

// ES6 絕對路徑
import utils from '/utils.js';

// CommonJS 相對路徑
var utils = require('./../utils.js');

// CommonJS 絕對路徑
var utils = require('/utils.js');

相對路徑是相對當前目錄。絕對路徑是相對入口文件,這個案例中是 main.js

我須要使用文件後綴麼?

不,你不須要去特地去使用 .js,可是若是你引入以後高亮會更好。你可能有一些 .js 文件和一些 .jsx 文件,甚至一些圖片和 css 能夠用 Webpack 引入,甚至能夠直接引入 node_modules 裏的代碼和特殊文件。

記住,Webpack 只是一個模塊合併!也就是說你能夠設置他去加載任何你寫的匹配,只要有一個加載器。咱們稍後會繼續深刻這個話題。

剩下全文地址:
全文地址

相關文章
相關標籤/搜索