標籤:

Webpack傻瓜指南(二)開發和部署技巧

該文章寫於兩年前,期間 webpack 已經發生了重大的 break change, 這期間作者也學到了很多新的知識,這篇文章的一些內容也已經不再適用,所以作者更新了 webpack2 的新教程,可以直接前往這裡:vikingmute/webpack-for-fools

注意啦:如果你還沒有看第一篇 請先看下第一篇的基礎知識:Webpack傻瓜式指南(一) - 前端外刊評論 - 知乎專欄 然後再來閱讀這一篇

上一章講了webpack的最基本基本用法,出乎意料的受到大家的歡迎,這一節講更深入的技巧,這一節也更深入大家做項目的實戰經驗,一個項目分為開發和上線兩個大的階段,那麼我們的技巧就分成這兩大塊來分開講解。

開發技巧

啟用source-map

現在的代碼是合併以後的代碼,不利於排錯和定位,只需要在config中添加

...n devtool: eval-source-map,n ...n

這樣出錯以後就會採用source-map的形式直接顯示你出錯代碼的位置。

配置webpack-dev-server代理

既然常用webpack做React一類的SPA,那麼一個典型的例子就是前後端分離。後端是一個RESTful的server不管用什麼寫的。假定在本機他是類似localhost:5000/api/*這類的請求,現在添加配置讓ajax請求可以直接proxy過去。

devServer: {n hot: true,n inline: true,n //其實很簡單的,只要配置這個參數就可以了n proxy: {n /api/*: {n target: http://localhost:5000,n secure: falsen }n }n },n

重啟以後 發現/api/*的請求都代理到http://localhost:5000去了~

更多的方法可以看官方文檔 Webpack dev server proxy

使用preLoaders和postLoaders

也許你想在寫代碼的時候檢查自己的js是否符合jshint的規範,那麼隆重推薦preLoaders和postLoaders,上一節我們已經非常了解loaders了,用它來處理各種類型的文件。perLoaders顧名思義就是在loaders執行之前處理的,webpack的處理順序是perLoaders - loaders - postLoaders。

安裝jshint

npm install jshint-loader --save-devn

在config文件中配置

module: {n...n //和loaders一樣的語法,很簡單n perLoaders: [n {n test: /.jsx?$/,n include: APP_PATH,n loader: jshint-loadern }n ]n}nn...n//配置jshint的選項,支持es6的校驗njshint: {n "esnext": truen},n

好了 現在每次npm run start的時候就可以看到jshint的提示信息啦

載入jQuery plugin或者其他legacy第三方庫

這個是非常有用的內容!

你的項目有時候會要載入各種各樣的第三方庫,一些老的庫不支持AMD或者CommonJS等一些先進的格式,比如一些jQuery的插件,它們都依賴jQuery,如果直接引用就會報錯 jQuery is not undefined這類的錯誤,有幾種方法解決

先創建一個jQuery plugin: plugin.js

(function ($) {n const shade = "#556b2f";n $.fn.greenify = function() {n this.css( "color", shade );n return this;n };n}(jQuery));n

第一種方法 使用webpack.ProvidePlugin

webpack提供一個插件 把一個全局變數插入到所有的代碼中,在config.js裡面配置

...n plugins: [n new HtmlwebpackPlugin({n title: Hello World appn }),n //provide $, jQuery and window.jQuery to every scriptn new webpack.ProvidePlugin({n $: "jquery",n jQuery: "jquery",n "window.jQuery": "jquery"n })n ]n ...n

在js中引用

...n//這個也不需要了 因為$, jQuery, window.jQuery都可以直接使用了n//import $ from jquery;nimport ./plugin.js;n...nmyPromise.then((number) => {n $(body).append(<p>promise result is + number + now is + moment().format() + </p>);n //call our jquery plugin!n $(p).greenify();n});n...n

發現我們插入的p裡面的顏色已經變成了綠色!

第二種方法 使用imports-loader

先安裝這個loader

npm install imports-loader --save-devn

然後在入口js中

//注意這種寫法 我們把jQuery這個變數直接插入到plugin.js裡面了n//相當於在這個文件的開始添加了 var jQuery = require(jquery);nimport imports?jQuery=jquery!./plugin.js;nn//後面的代碼一樣nmyPromise.then((number) => {n $(body).append(<p>promise result is + number + now is + moment().format() + </p>);n //call our jquery plugin!n $(p).greenify();n});n

部署上線

剛才說的各種情況都是在開發時候的情況,那麼假如項目已經開發完了,需要部署上線了。我們應該新創建一個單獨的config文件,因為部署上線使用webpack的時候我們不需要一些dev-tools,dev-server和jshint校驗等。

複製我們現有的config文件,命名為 webpack.production.config.js,將裡面關於 devServer等和開發有關的東西刪掉。

在package.json中添加一個命令。

"scripts": {n "start": "webpack-dev-server --hot --inline",n "build": "webpack --progress --profile --colors --config webpack.production.config.js"n },n

當要上線的時候,運行

npm run buildn

可以發現build文件夾中生成了所有東西。

分離app.js和第三方庫

現在我們build出來的只有一個bundle.js 如果第三方庫很多的話,會造成這個文件非常大,減慢載入速度,現在我們要把第三方庫和我們app本身的代碼分成兩個文件。

修改entry入口文件

entry: {n app: path.resolve(APP_PATH, index.js),n //添加要打包在vendors裡面的庫n vendors: [jquery, moment]n },n

添加CommonsChunkPlugin

plugins: [n //這個使用uglifyJs壓縮你的js代碼n new webpack.optimize.UglifyJsPlugin({minimize: true}),n //把入口文件裡面的數組打包成verdors.jsn new webpack.optimize.CommonsChunkPlugin(vendors, vendors.js),n new HtmlwebpackPlugin({n title: Hello World appn })n ]n

添加完畢 運行npm run build

在build文件夾中發現如下結構

  • budle.js
  • index.html
  • vendors.js

生成多頁面

應用不可能都是SPA,不可能只生成一個html文件,如果想生成多個html頁面這麼玩?其實也是很簡單的: 現在的需求是這樣的,有兩個頁面,一個叫index.html 它需要引用vendors.js和app.js這兩個文件,還有一個mobile.html頁面他要引用vendors.js和mobile.js這兩個文件。

首先新建一個叫mobile.js的入口文件,比app.js更簡單一些

import ./main.scss;nimport $ from jquery;nimport imports?jQuery=jquery!./plugin.js;nn$(document).ready(function() {n let app = document.createElement(div);n app.innerHTML = <h1>Hello World</h1>;n document.body.appendChild(app);n $(h1).greenify();n});n

在config裡面配置

entry: {n //三個入口文件,app, mobile和 vendorsn app: path.resolve(APP_PATH, index.js),n mobile: path.resolve(APP_PATH, mobile.js),n vendors: [jquery, moment]n },n output: {n path: BUILD_PATH,n //注意 我們修改了bundle.js 用一個數組[name]來代替,他會根據entry的入口文件名稱生成多個js文件,這裡就是(app.js,mobile.js和vendors.js)n filename: [name].jsn },n

原來我們是沒有模版文件的,原來利用的HtmlWebpackPlugin的默認模版。誰想到這偉大的插件還可以自定義模版。 所以新建一個專門放模版的文件夾templates,在裡面加兩個模版文件index.html 和 mobile.html

index.html

<!DOCTYPE html>n<html>n <head>n <title>{%= o.htmlWebpackPlugin.options.title %}</title>n </head>n <body>n <h3>Welcome to webpack</h3>n </body>n</html>n

mobile.html

<!DOCTYPE html>n<html>n <head>n <title>{%= o.htmlWebpackPlugin.options.title %}</title>n </head>n <body>n <h3>Welcome to mobile page</h3>n </body>n</html>n

繼續配置config.js,現在讓HtmlwebpackPlugin可以生成多個文件

...n//Template的文件夾路徑nvar TEM_PATH = path.resolve(ROOT_PATH, templates);n...nplugins: [n ...n //創建了兩個HtmlWebpackPlugin的實例,生成兩個頁面n new HtmlwebpackPlugin({n title: Hello World app,n template: path.resolve(TEM_PATH, index.html),n filename: index.html,n //chunks這個參數告訴插件要引用entry裡面的哪幾個入口n chunks: [app, vendors],n //要把script插入到標籤里n inject: bodyn }),n new HtmlwebpackPlugin({n title: Hello Mobile app,n template: path.resolve(TEM_PATH, mobile.html),n filename: mobile.html,n chunks: [mobile, vendors],n inject: bodyn })n ...n]n

然後運行

npm run buildn

看看生成好的偉大的文件,沒問題!

  • app.js
  • mobile.js
  • vendors.js
  • index.html
  • mobile.html

看看引用的對應關係,完美!!

index.html

<body>n <h3>Welcome to webpack</h3>n <script src="vendors.js"></script><script src="app.js"></script>n</body>n

mobile.html

<body>n <h3>Welcome to mobile page</h3>n <script src="vendors.js"></script><script src="mobile.js"></script>n</body>n

生成Hash名稱的script來防止緩存

經典問題,代碼更新了,但是瀏覽器有緩存,到時候就傻了。 怎麼解決,換名字唄。可以直接在後面加參數,也可以直接換掉文件名字。 webpack提供給了我們非常簡單的方法,基於文件的md5,只要把

output: {n path: BUILD_PATH,n //只要再加上hash這個參數就可以了n filename: [name].[hash].jsn},n

運行完build以後,看看生成的文件,很完美~

index.html

<body>n <h3>Welcome to webpack</h3>n <script src="vendors.js"></script><script src="app.b6641abee64c999d95c1.js"></script>n</body>n

好了,你現在了解webpack作為一個module bundler的精髓了吧,把我們的例子做成一個圖,幫助你理解一下。

結語

第二部分到這裡結束,這一節討論很多webpack的使用技巧,看起來比較瑣碎,但是在你工作中也許會很實用,下一部分會出現大家都期待的高大上的東西,Webpack和React和Backbone等的結合。

很硬的鏈接

repo的代碼已經更新,想看所有源碼的可以clone下 vikingmute/webpack-basic-starter · GitHub

同時這一系列關於Webpack的文章也可以在github找到 vikingmute/webpack-for-fools · GitHub

微博關註:前端外刊評論


推薦閱讀:

React 事件系統分析與最佳實踐
前端開發每周閱讀清單:PWA 將與安卓原生平起平坐
基於 Webpack 的應用包體尺寸優化
React 實現一個漂亮的 Table

TAG:React | webpack |