webpack+react專案初體驗——記錄我的webpack環境配置

yisha0307發表於2017-02-05

這兩天學習了一些webpack的知識,loaders+plugins真的很強大!不過配置起來也很複雜,看了一些文章,自己也寫了專案練手,寫下來加深自己的印象。

首先,非常非常推薦的幾篇文章,初學者一定要看!
<入門Webpack,看這篇就夠了>
http://www.jianshu.com/p/42e1…
(標題一點也不誇張,非常適合0基礎)
<Webpack傻瓜式指南>
https://zhuanlan.zhihu.com/p/…
https://zhuanlan.zhihu.com/p/…
https://zhuanlan.zhihu.com/p/…
(這個系列有三篇文章,第三章是一個webpack+react的小專案,跟著做一遍會很有收穫~)

另外,也推薦看一下阮一峰es6書中module這一章,弄清楚export/import/export default等等命令,畢竟webpack的各個模組是靠export/import/require(commonjs)連結起來的,所以這些都要掌握。

具體到專案的話,webpack有幾個比較基本的概念:
1、loaders:通過不同的loaders,webpack可以處理各式各樣的檔案,然後打包到一個檔案中(比如bundle.js);
2、plugins:plugins是為了擴充webpack的功能的,和loaders不同的是,loader是用來處理單個檔案的(比如json-loader處理.json,sass-loader處理.scss),但是plugins是直接對整個構建過程進行處理(比如自動生成html檔案的html-webpack-plugin);
3、others: 這些我也不知道要歸到哪裡去,但是在配置中也是必不可少,包括webpack-dev-server/source-map等等,後面會具體說;
4、配置檔案:我這個小專案包括的檔案有.babelrc(用來處理babel),webpack.config.js(webpack專案基礎配置檔案),package.json(這個檔案會記錄所有的devDependencies)。

然後我們就一項一項來分析吧:

1、loaders

1) style-loader / css-loader / sass-loader

這幾個loader用來處理.css和.scss檔案,一起安裝用空格隔開:

 $ npm install --save-dev style-loader css-loader sass-loader

同時修改webpack.config.js:

module: {
        loaders: [
        {
            test: /.scss$/,
            //loaders是依靠正規表示式來測試這個檔案是不是這個loader來處理,所以test不能少
            loaders: [`style-loader`,`css-loader`,`sass-loader`],
            //"-loader"一定要寫,不然會報錯
            //loaders的處理順序是從右向左,就是會先用sass-loader,其次css-loader,再次style-loader
        }  
        
2) url-loader

這個loader是用來處理url連結,就是圖片或者其他靜態檔案。
安裝:

$ npm install --save-dev url-loader

webpack.config.js (寫在module裡):

    {
            test: /.(png|jpq)$/,
            loader: `url? limit = 40000`
        }
3) json-loader

安裝和配置和之前一樣~用來處理json檔案

4) babel相關的loaders:

這個包括的就比較多,有babel-core/babel-loader/babel-preset-es2015/babel-preset-react,後面兩個是為了寫es6和react服務。

    //webpack.config.js
        {
            test: /.jsx$/,
            loader:`babel-loader`,
            include: APP_PATH,
            //這個include是說只對這裡面的檔案負責,還有一個對應的exclude,就是忽略範圍內的檔案, 比如:exclude: `./node_modules/`;
        }

另外因為babel需要寫的選項比較多,可以配一個.babelrc在根目錄下:

//.babelrc
{
    `presets`:[`react`,`es2015`],
    }
}

以上就是用的比較多的loaders,配完這些webpack就可以處理json/sass/es6啦~

2、plugins

1) html-webpack-plugin

這個外掛的作用就是自動生成html(其實也可以自己寫,就是加了個bundle.js的script而已,不過感覺比較酷):
plugins安裝好了之後要放在webpack.config.js的plugins的陣列裡,不要寫在modules裡呀~

    //webpack.config.js
    plugins: [
        new HtmlWebpackPlugin({
        //在最前面先定義下HtmlWebpackPlugin--
        //var HtmlWebpackPlugin = require(`html-webpack-plugin`);
            title: `searchBar`,    //配合html-webpack-plugin的配置
        })
    ],
2) react-transform-hrm

HMR是一個webpack外掛,它讓你能瀏覽器中實時觀察模組修改後的效果,但是如果你想讓它工作,需要對模組進行額外的配額;
Babel有一個叫做react-transform-hrm的外掛,可以在不對React模組進行額外的配置的前提下讓HMR正常工作;
安裝:

$ npm install --save-dev babel-plugin-react-transform react-transform-hmr

配置:

//webpack.config.js (plugins裡)
new webpack.HotModuleReplacementPlugin();

然後修改下.babelrc:

{
  "presets": ["react", "es2015"],
  "env": {
    "development": {
    "plugins": [["react-transform", {
       "transforms": [{
         "transform": "react-transform-hmr",

         "imports": ["react"],

         "locals": ["module"]
       }]
     }]]
    }
  }
}

這樣在使用react的時候就可以熱載入模組了~

3)UglifyJsPlugin:

壓縮JS程式碼;

4)ExtractTextPlugin:

分離CSS和JS檔案;
以上兩個外掛這次沒有用,先記下來下次用過了再來補~

3、others

1) webpack-dev-server

用來構建本地開發的伺服器,可以讓瀏覽器監測程式碼的修改,並自動重新整理修改後的結果;
安裝:

$npm --save-dev webpack-dev-server

webpack-dev-server有以下幾個配置選項:

  • contentBase:預設webpack-dev-server會為根資料夾提供本地伺服器,如果想為另外一個目錄下的檔案提供本地伺服器,應該在這裡設定其所在目錄(本例設定到“public”目錄)

  • port:設定預設監聽埠,如果省略,預設為”8080“

  • inline:設定為true,當原始檔改變時會自動重新整理頁面

  • historyApiFallback:在開發單頁應用時非常有用,它依賴於HTML5 history API,如果設定為true,所有的跳轉將指向index.html

    //webpack.config.js
    devServer: {
               contentBase: "./public",//本地伺服器所載入的頁面所在的目錄
               historyApiFallback: true,//不跳轉
               inline: true//實時重新整理
           }
    
//package.json
 "scripts": {
    "start": "webpack-dev-server --inline",
  }

然後就可以用http://localhost:8080/index.html預覽專案啦~

2)source-map:

source maps提供了一種對應編譯檔案和原始檔的方法,使得編譯後的程式碼可讀性更高,也更容易除錯。
在學習階段和寫中、小型專案的時候,用eval-source-map,如果是開發大型專案可以用cheap-module-eval-source-map,會更快。

//webpack.config.js
devtool: `eval-source-map`,
3) 第三方庫:

這個就包括一些我們比較瞭解的比如react/react-dom/jquery/moment/bootstrap等等啦,配置起來也很方便,首先是安裝:

$npm --save-dev jquery moment react react-dom
$npm install bootstrap@4.0.0-alpha.2 --save-dev

然後在你需要的js檔案裡引用這些庫:

import React from `react`;
import ReactDOM from `react-dom`;

var $ = require(`jquery`);
var moment = require(`moment`);

然後就可以愉快地寫各種js、jsx檔案啦~

4、配置檔案

最後我們來講一講幾個配置檔案的問題:

1) webpack.config.js

上面提到的都是各種肢解,我這次的config檔案是這樣的:

var path = require(`path`);
var HtmlWebpackPlugin = require(`html-webpack-plugin`);
var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, `app`);
var BUILD_PATH = path.resolve(ROOT_PATH, `build`);

module.exports = {
    devtool: `eval-source-map`,
    entry: __dirname + `/app/index.jsx`,
//webpack的入口檔案只有一個,所以寫的所有components甚至包括css/json什麼的,都要引用在這裡
output:{
    path: __dirname +`/public`,
    filename: `bundle.js`,
},
//我這邊是新建了一個folder叫public,用來放index.html和bundle.js
devServer: {
    contentBase: "./public",//本地伺服器所載入的頁面所在的目錄
    historyApiFallback: true,//不跳轉
    inline: true//實時重新整理
},
plugins: [
    new HtmlWebpackPlugin({
        title: `searchBar`,    //配合html-webpack-plugin的配置
    })
],
module: {
    loaders: [
    {
        test: /.scss$/,
        loaders: [`style-loader`,`css-loader`,`sass-loader`],
    },{
        test: /.(png|jpq)$/,
        loader: `url? limit = 40000`
    },{
        test: /.jsx$/,
        loader:`babel-loader`,
        include: APP_PATH,
    }]
},
resolve:{
        extensions: [``,`.js`, `.jsx`]
    },
};
2) package.json

這個檔案會在你最開始npm init的時候就生成,一路回車就可以,後來都可以改~

{
  "name": "serach-bar",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --progress --profile --colors --hot",
    "build": "webpack --progress --profile --colors",
    "test": "karma start"
  },
 //scripts這邊可以改一下,改start可以,在終端用npm start,上面有例子~這邊的dev要改的話在終端的命令是`npm run dev;
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.22.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-react-transform": "^2.0.2",
    "babel-preset-es2015": "^6.22.0",
    "babel-preset-react": "^6.22.0",
    "babel-preset-react-hmre": "^1.1.1",
    "bootstrap": "^4.0.0-alpha.2",
    "css-loader": "^0.26.1",
    "file-loader": "^0.10.0",
    "html-webpack-plugin": "^2.28.0",
    "jquery": "^3.1.1",
    "jshint": "^2.9.4",
    "jshint-loader": "^0.8.3",
    "json-loader": "^0.5.4",
    "node-sass": "^4.5.0",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-transform-catch-errors": "^1.0.2",
    "react-transform-hmr": "^1.0.4",
    "redbox-react": "^1.3.3",
    "sass-loader": "^4.1.1",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^2.2.1",
    "webpack-dev-server": "^2.3.0"
  }
}

裝了很多dev,其實用不著那麼多哈哈~

3) .babelrc
{
    `presets`:[`react`,`es2015`],
    `env`:{
    `development`:{
    `presets`:[`react-hmre`]
    }
    }
}

ok,這樣就差不多啦~另外還要注意的是index.jsx/index.js,所有的components都要引用過來,css/scss也是,css檔案的話最好有一個main.css進行整合,這樣不會漏掉。
看一眼這次的index.jsx:

// `注意這些import
import `../node_modules/bootstrap/scss/bootstrap.scss`;
import `./main.scss`;
import React from `react`;
import ReactDOM from `react-dom`;
import Search from `./components/search`;
import Plist from `./components/plist`;

class App extends React.Component{
    constructor(props){
        super(props);
        this.state={`keyword`:``};
        this.refreshKeyword = this.refreshKeyword.bind(this);
    }
    refreshKeyword(name){
        this.setState({`keyword`:name});
    }
    render(){
        return (
            <div className = `container`>
                <section className = `jumbotron`>
                    <h3 className =`jumbotron-heading`>Search Github Users</h3>
                    <Search sendAction = {this.refreshKeyword} />
                </section>
                <Plist keyword={this.state.keyword} />
            </div>
                )
    }
};

const app = document.createElement(`div`);
document.body.appendChild(app);
ReactDOM.render(<App />, app);

恩,差不多就是這樣啦~~專案初始化的時候不要忘記npm install –save-dev webpack哦!coding愉快!

相關文章