webpack配置React開發環境(上)

牧云云發表於2017-03-08

Webpack 是一個前端資源載入/打包工具,我們部門的一條主要技術棧就是Webpack+React+ES6+node,雖然之前自己做個人專案也接觸好多次Webpack,但是自己並沒有研讀總結過Webpack的知識點,讀了wepack-demos,這些demos雖然是基於webpack@1.x的,但是舉例得蠻簡潔明瞭,所以這次就簡單翻譯此文的一些重點。

什麼是Webpack?

Webpack是一個前端資源載入/打包工具,只需要相對簡單的配置就可以提供前端工程化需要的各種功能,並且如果有需要它還可以被整合到其他比如 Grunt / Gulp 的工作流。

安裝 Webpack:npm install -g webpack。

Webpack 使用一個名為 webpack.config.js 的配置檔案。

// webpack.config.js
module.exports = {
  entry: `./main.js`,
  output: {
    filename: `bundle.js`
  }
};

一些你應該知道的命令:

  • webpack —— 進行一次編譯
  • webpack -p —— 進行一次編譯(壓縮成一行)
  • webpack –watch —— 持續編譯
  • webpack -d  —— 編譯完成後包含一個maps檔案
  • wepack –colors —— 使壓縮檔案變漂亮(我暫時沒看出來)

在開發應用程式時,可以在package.json檔案中編寫scripts欄位,如下所示:

// package.json
{
  // ...
  "scripts": {
    "dev": "webpack-dev-server --devtool eval --progress --colors",
    "deploy": "NODE_ENV=production webpack -p"
  },
  // ...
}

入口檔案

入口檔案是一個Webpack將會讀取它並將它編譯成bundle.js的檔案

demo01:單個入口檔案:

// webpack.config.js
module.exports = {
  entry: `./main.js`,
  output: {
    filename: `bundle.js`
  }
};

demo02:多個入口檔案:(它對多頁面app是非常有用的)

// index.html
<html>
  <body>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>

// webpack.config.js
module.exports = {
  entry: {
    bundle1: `./main1.js`,
    bundle2: `./main2.js`
  },
  output: {
    filename: `[name].js`
  }
};

Babel-loader

載入器是前處理器,它轉換您的應用程式的資原始檔(更多資訊)。例如,Babel-loader可以將JSX / ES6檔案轉換為JS檔案。官方文件有一個完整的載入器列表

// webpack.config.js
module: {
    loaders:[
      {
        test: /.js[x]?$/,
        exclude: /node_modules/,
        loader: `babel-loader?presets[]=es2015&presets[]=react`
      },
    ]
  }

或者
module: {
  loaders: [
    {
      test: /.jsx?$/,
      exclude: /node_modules/,
      loader: `babel`,
      query: {
        presets: [`es2015`, `react`]
      }
    }
  ]
}

CSS-loader

Webpack允許您在JS檔案中引用CSS,然後使用CSS-loader預處理CSS檔案。

// main.js
require(`./app.css`);
// webpack.config.js
module.exports = {
  entry: `./main.js`,
  output: {
    filename: `bundle.js`
  },
  module: {
    loaders:[
      { test: /.css$/, loader: `style-loader!css-loader` },
    ]
  }
};

注意,你必須使用兩個載入器來轉換CSS檔案。首先是CSS-loader讀取CSS檔案,另一個是Style-loader將Style標籤插入HTML頁面。不同的裝載器通過感嘆號(!)連結。

啟動伺服器後,index.html將具有內部樣式表。(demo04)

Image loader

// main.js
var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);

var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);

// index.html
<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>

// webpack.config.js
module.exports = {
  entry: `./main.js`,
  output: {
    filename: `bundle.js`
  },
  module: {
    loaders:[
      { test: /.(png|jpg)$/, loader: `url-loader?limit=8192` }
    ]
  }
};

url-loader轉換影像檔案。如果影像大小小於8192位元組,則將其轉換為資料URL;否則,它將被轉換為正常的URL。如你所見,問號(?)用於將引數傳遞到載入器。

啟動伺服器後,small.png和big.png將有以下URL。

<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">

UglifyJS Plugin(減少輸出)

Webpack有一個外掛系統來擴充套件其功能。例如,UglifyJs Plugin將縮小輸出(bundle.js)JS程式碼。(demo07)

// webpack.config.js
var webpack = require(`webpack`);
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
module.exports = {
  entry: `./main.js`,
  output: {
    filename: `bundle.js`
  },
  plugins: [
    new uglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
};

壓縮的效果如下:

// 壓縮前
var longVariableName = `Hello`;
longVariableName += ` World`;
document.write(`<h1>` + longVariableName + `</h1>`);

// 壓縮後
var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")

自動開啟瀏覽器&&自動建立index.html

此演示向您演示如何載入第三方外掛。 html-webpack-plugin可以為您建立index.html,並且當Webpack載入時,open-browser-webpack-plugin可以開啟一個新的瀏覽器選項卡。

// main.js
document.write(`<h1>Hello World</h1>`);

// webpack.config.js
var HtmlwebpackPlugin = require(`html-webpack-plugin`);
var OpenBrowserPlugin = require(`open-browser-webpack-plugin`);

module.exports = {
  entry: `./main.js`,
  output: {
    filename: `bundle.js`
  },
  plugins: [
    new HtmlwebpackPlugin({
      title: `Webpack-demos`,
      filename: `index.html`
    }),
    new OpenBrowserPlugin({
      url: `http://localhost:8080`
    })
  ]
};

環境標誌

您可以僅在具有環境標誌的開發環境中啟用一些程式碼(demo09)

// main.js
document.write(`<h1>Hello World</h1>`);

if (__DEV__) {
  document.write(new Date());
}

// index.html
<html>
<body>
  <script src="bundle.js"></script>
</body>
</html>

// webpack.config.js
var webpack = require(`webpack`);

var devFlagPlugin = new webpack.DefinePlugin({
  __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || `false`))
});

module.exports = {
  entry: `./main.js`,
  output: {
    filename: `bundle.js`
  },
  plugins: [devFlagPlugin]
};

然後現在將環境變數傳遞到webpack。

# Linux & Mac
$ env DEBUG=true webpack-dev-server

# Windows
$ set DEBUG=true
$ webpack-dev-server

Common chunk(抽出公用指令碼)

當多指令碼具有公共塊時,可以使用CommonsChunkPlugin將公共部分提取到單獨的檔案中。

// main1.jsx
var React = require(`react`);
var ReactDOM = require(`react-dom`);

ReactDOM.render(
  <h1>Hello World</h1>,
  document.getElementById(`a`)
);

// main2.jsx
var React = require(`react`);
var ReactDOM = require(`react-dom`);

ReactDOM.render(
  <h2>Hello Webpack</h2>,
  document.getElementById(`b`)
);

// index.html
<html>
  <body>
    <div id="a"></div>
    <div id="b"></div>
    <script src="init.js"></script>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>

// webpack.config.js
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
  entry: {
    bundle1: `./main1.jsx`,
    bundle2: `./main2.jsx`
  },
  output: {
    filename: `[name].js`
  },
  module: {
    loaders:[
      {
        test: /.js[x]?$/,
        exclude: /node_modules/,
        loader: `babel-loader`,
        query: {
          presets: [`es2015`, `react`]
        }
      },
    ]
  },
  plugins: [
    new CommonsChunkPlugin(`init.js`)
  ]
}

Vendor chunk

您還可以使用CommonsChunkPlugin從指令碼中將供應商庫提取到單獨的檔案中。(優化程式碼層面)

// main.js
var $ = require(`jquery`);
$(`h1`).text(`Hello World`);

// index.html
<html>
  <body>
    <h1></h1>
    <script src="vendor.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>

// webpack.config.js
var webpack = require(`webpack`);

module.exports = {
  entry: {
    app: `./main.js`,
    vendor: [`jquery`],
  },
  output: {
    filename: `bundle.js`
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin(/* chunkName= */`vendor`, /* filename= */`vendor.js`)
  ]
};

如果你想要一個模組作為變數在每個模組,如使$和jQuery可用在每個模組沒有寫require(“jquery”)。你應該使用ProvidePlugin(官方文件)。

// main.js
$(`h1`).text(`Hello World`);


// webpack.config.js
var webpack = require(`webpack`);

module.exports = {
  entry: {
    app: `./main.js`
  },
  output: {
    filename: `bundle.js`
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery"
    })
  ]
};

熱更新

熱模組替換(HMR)交換,新增或刪除模組,而應用程式正在執行,而沒有頁面重新載入。

您有兩種方法通過webpack-dev-server啟用熱模組更換。

(1)在命令列中指定–hot和–inline

$ webpack-dev-server --hot --inline

選項的含義:

  • –hot: 新增HotModuleReplacementPlugin並將伺服器切換到熱模式。
  • –inline: 將webpack-dev-server執行時嵌入到bundle中。
  • –hot –inline: 還新增了webpack/hot/dev-server條目。

(2)修改webpack.config.js檔案(demo15)

  • 新增新webpack.HotModuleReplacementPlugin() 的外掛
  • 新增webpack/hot/dev-server 和 webpack-dev-server/client?http://localhost:8080 到輸入欄位
// webpack.config.js
var webpack = require(`webpack`);
var path = require(`path`);

module.exports = {
  entry: [
    `webpack/hot/dev-server`,
    `webpack-dev-server/client?http://localhost:8080`,
    `./index.js`
  ],
  output: {
    filename: `bundle.js`,
    publicPath: `/static/`
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
  module: {
    loaders: [{
      test: /.jsx?$/,
      exclude: /node_modules/,
      loader: `babel-loader`,
      query: {
        presets: [`es2015`, `react`]
      },
      include: path.join(__dirname, `.`)
    }]
  }
};
// App.js
import React, { Component } from `react`;

export default class App extends Component {
  render() {
    return (
      <h1>Hello World</h1>
    );
  }
}

// index.js
import React from `react`;
import ReactDOM from `react-dom`;
import App from `./App`;

ReactDOM.render(<App />, document.getElementById(`root`));

// index.html
<html>
  <body>
    <div id=`root`></div>
    <script src="/static/bundle.js"></script>
  </body>
</html>

有用的連結

 下回會學習總結webpack2的配置相關總結,有不錯的文章歡迎分享。

作者:牧云云

出處:http://www.cnblogs.com/MuYunyun/”

本文版權歸作者和部落格園所有,歡迎轉載,轉載請標明出處。

如果您覺得本篇博文對您有所收穫,請點選右下角的 [推薦],謝謝!


相關文章