天天看點

Vue08-webpack使用

什麼是Webpack

  本質上,webpack是一個現代JavaScript應用程式的靜态子產品打包器(module bundler)。當webpack處理應用程式時,它會遞歸地建構一個依賴關系圖(dependency graph),其中包含應用程式需要的每個子產品,然後将所有子產品打包成一個或多個bundle。

  Webpack是當下最熱門地前端資源子產品化管理和打包工具,它可以将許多松散耦合地子產品按照依賴和規則打包成符合生産環境部署地前端資源。還可以将按需加載地子產品進行代碼分離,等到實際需要時再異步加載。通過loader轉換,任何形式地資源都可以當作子產品,比如Common JS、AMD、ES 6、CSS、JSON、Coffee Script、LESS等。

  伴随着移動互聯的大潮,當今越來越多的網站已經從網頁模式進化到了WebApp模式。它們運作在現代浏覽器裡,使用HTML 5、CSS 3、ES 6等新的技術來開發豐富的功能,網頁已經不僅僅是完成浏覽器的基本需求;WebApp通常是一個SPA(單頁面應用),每一個視圖通過異步的方式加載,這導緻頁面初始化和使用過程中會加載越來越多的JS代碼,這給前端的開發流程和資源組織帶來了巨大挑戰。

    前端開發和其它開發工作的主要差別,首先是前端基于多語言、多層次的編碼群組織工作,其次前端産品的傳遞是基于浏覽器的,這些資源是通過增量加載的方式運作到浏覽器端,如何在開發環境組織好這些碎片化的代碼和資源,并且保證它們在浏覽器端快速、優雅的加載和更新,就需要一個子產品化系統,這個理想中的子產品化系統是前端工程師多年來一直探索的難題。

子產品化的演進

Script标簽

<script src = "module1.js"></script>
<script src = "module2.js"></script>
<script src = "module3.js"></script>
           

      這是最原始的JavaScript檔案加載方式,如果把每一個檔案看作是一個子產品,那麼它們的接口通常是暴露在全局作用域下,也就是定義在window對象中,不同子產品的調用都是一個作用域。

      這種原始的加載方式暴露了一些顯而易見的弊端:

  • 全局作用域下容易造成變量沖突
  • 檔案隻能按照

    <script>

    的書寫順序進行加載
  • 開發人員必須主管解決子產品和代碼庫的依賴關系
  • 在大型項目中各種資源難以管理,長期積累的問題導緻代碼庫混亂不堪

CommonJS

  伺服器端的NodeJS遵循CommonJS規範,該規範核心思想是允許子產品通過require方法來同步加載所需依賴的其它子產品,然後通過exports或module.exports來導出需要暴露的接口。

require("module");
require("../module.js");
export.doStuff = function(){};
module.exports = someValue;
           

優點:

  • 伺服器端子產品便于重用
  • NPM中已經有超過45萬個可以使用的子產品包
  • 簡單易用

缺點:

  同步的子產品加載方式不适合在浏覽器環境中,同步意味着阻塞加載,浏覽器資源是異步加載的

  不能非阻塞的并行加載多個子產品

實作:

  • 服務端的NodeJS
  • Browserify,浏覽器端的CommonJS實作,可以使用NPM的子產品,但是編譯打包後的檔案體積較大
  • modules-webmake,類似Browserify,但不如Browserify靈活
  • wreq,Browserify的前身

AMD

  AMD(Asynchronous Module Definition) 是一種定義了寫入子產品接口和加載子產品接口的 JavaScript 規範。

define([name: String], [dependencies: String[]], factoryMethod: function(...))
require(dependencies: String[], [callback: function(...)])
           
  • 适合在浏覽器環境中異步加載子產品
  • 可以并行加載多個子產品
  • 提高了開發成本,代碼的閱讀和書寫比較困難,子產品定義方式的語義不暢
  • 不符合通用的子產品化思維方式,是一種妥協的實作
  • RequireJS
  • curl

CMD

  Commons Module Definition規範和AMD很相似,盡保持簡單,并與CommonsJS和NodeJS的Modules規範保持了很大的相容性。

define(function(require,exports,module){
	var $=require("jquery");
	var Spinning = require("./spinning");
	exports.doSomething = ...;
	module.exports=...;
});
           
  • 依賴就近,延遲執行
  • 可以很容易在NodeJS中運作缺點
  • 依賴SPM打包,子產品的加載邏輯偏重

實作:

  • Sea.js
  • coolie

ES6子產品

  ECMAScript 6标準增加了JavaScript語言層面的子產品體系定義。ES 6子產品的設計思想,是盡量靜态化,使編譯時就能确定子產品的依賴關系,以及輸入和輸出的變量。CommonJS和AMD子產品,都隻能在運作時确定這些東西。

import "jquery"
export function doStuff(){}
module "localModule"{}
           
  • 容易進行靜态分析
  • 面向未來的EcmaScript标準

缺點:

  • 原生浏覽器端還沒有實作該标準
  • 全新的指令,新版的Node JS才支援
  • Babel

大家期望的子產品

  系統可以相容多種子產品風格,盡量可以利用已有的代碼,不僅僅隻是JavaScript子產品化,還有CSS、圖檔、字型等資源也需要子產品化

安裝Webpack

  WebPack是一款子產品加載器兼打包工具, 它能把各種資源, 如JS、JSX、ES 6、SASS、LESS、圖檔等都作為子產品來處理和使用。

安裝:

npm install webpack -g
npm install webpack-cli -g
           

測試安裝成功:

webpack -v
webpack-cli -v
           
Vue08-webpack使用

使用webpack

1、建立項目(建立一個名為webpack-study的空檔案夾,用idea打開)

2、建立一個名為modules的目錄,用于防止JS子產品等資源檔案

3、在modules下建立子產品檔案

  • hello.js
// 暴露一個方法
exports.sayHi = function () {
    document.write("<div>Edgar學ES6</div>")
}
           
  • 在modules下建立一個名為main.js的入口檔案,用于打包時設定entry屬性
// require 導入一個子產品,就可以調用這個子產品中的方法了
var hello = require("./hello");
hello.sayHi();
           
  • 在項目目錄下建立webpack.config.js配置檔案,以下為簡易版,詳細版在文章最底部
module.exports = {
    entry: './modules/main.js',
    output: {
        filename: "./js/bundle.js"
    }
}
           
  • 使用

    webpack

    指令打包
# 參數--watch 用于監聽變化,可以實作熱更新
webpack --watch
           
Vue08-webpack使用
  • 在項目目錄下建立HTML頁面,如index.html,導入webpack打包後的JS檔案
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="dist/js/bundle.js"></script>
</body>
</html>
           
  • 運作HTML看效果
Vue08-webpack使用

完整的目錄結構

Vue08-webpack使用

webpack.config.js

配置檔案

  • entry:入口檔案, 指定Web Pack用哪個檔案作為項目的入口
  • output:輸出, 指定WebPack把處理完成的檔案放置到指定路徑
  • module:子產品, 用于處理各種類型的檔案
  • plugins:插件, 如:熱更新、代碼重用等
  • resolve:設定子產品如何被解析
  • watch:監聽, 用于設定檔案改動後直接打包
module.exports = {
	entry:"",
	output:{
		path:"",
		filename:""
	},
	module:{
		loaders:[
			{test:/\.js$/,;\loade:""}
		]
	},
	plugins:{},
	resolve:{},
	watch:true
}