在學習 Webpack 以前,咱們須要瞭解一個概念:模塊。javascript
若是你曾學過 Java , C# 之類的語言,必定會知道 Java 中的 import 或 C# 中的 using 吧?css
好比:我想在 C# 中進行數據庫操做,我只須要在代碼頭部加上 下面這兩段代碼便可。html
using System.Data;
using System.Data.SqlClient;
複製代碼
這兩段代碼能夠當作 兩個與數據庫操做相關的模塊。 當咱們需求是數據庫,或者是讀取 IO 等其餘操做,咱們便加載其餘不一樣的模塊。前端
很明顯,這實現了編程中的一個很是重要的功能 按需加載。java
在前端中 模塊又該如何定義呢? 按照我我的的理解:jquery
<div class="layer">
<div><%= name %></div>
<% for(var i = 0; i < People.length;++i) { %>
<%= People[i] %>
<% } %>
</div>
複製代碼
header{
display:block;
}
header h1{
font-size: 60px;
}
複製代碼
let People = { name: "Simon" } ;
module.exports = People;
複製代碼
而咱們又該怎樣實現 在前端中加載模塊呢?webpack
下面是兩個很常見的例子:es6
在 Less 中web
@import "header";
@import "layout";
@import "footer";
複製代碼
在 Javascript數據庫
// CommonJS
const $ = require("jQuery");
//es6
let People = { name: "Simon" } ;
module.exports = People;
import "./layer.less";
import tpl from "./layer.ejs";
複製代碼
若是你直接運行以上代碼,瀏覽器並不會解析,這個時候,就要依靠 Webpack 了!
Webpack 是一款目前很是流行的前端模塊打包工具,能夠將項目中所加載的模塊進行打包,以及將 一些瀏覽器不支持的語言進行轉換。
Webpack 的打包原理是 先找到入口文件,遞歸探索出全部依賴的模塊,最後 利用 Loader 進行不一樣文件類型的處理,打包成一個 Javascript 文件。
其中,Webpack 的兩個最核心原理分別是:
固然 Webpack 的做用不止加載模塊這麼簡單,前端的經常使用需求一般均可以實現:利用 Loader 轉換 es6 、 Less 、 Typescript ,還可利用插件 開發多頁面應用,等等諸多強大功能。
下面,我將講解 Webpack 的具體使用和配置。
我通常在項目中使用 Webpack,都是先執行下面這四條命令進行 Webpack 的安裝
npm install -g webpack
在全局安裝 Webpack,第一次使用時 執行
npm install --save-dev webpack
將 Webpack 安裝到你的項目
npm init
npm初始化,會詢問你的項目信息,能夠回車跳過
npm install --save-dev webpack-dev-server
在當前項目,安裝 Webpack 服務器
安裝完成後,即是創建配置文件了。
在項目根目錄下新建名爲 webpack.config.js 的文件,
基本上 一個配置文件的大致結構就是下面這樣:
modules.export={
entry:{
/* 入口文件 */
},
output:{
/* 出口文件 */
},
module:{
/* Loader */
rules:[{},{},{}]
},
plugins:[
/* 插件 */
],
devtool: ...
devServer: {...}
resolve:{...}
}
複製代碼
咱們下面就先分析 modules.export 各個屬性
entry 表明是入口文件,Webpack 工做的開始。
Webpack 會遞歸的探索出 入口文件中所依賴的模塊,並按照順序 利用 Loader 進行處理。
官網給出了其 3 種數據類型:
entry: "app.js";
複製代碼
數組
數組中的每一項都會被打包,造成互不依賴的文件
entry: ["app.js","main.js"];
複製代碼
對象
對象中的每個屬性都會被打包,造成互不依賴的文件
entry:{
app: "./src/js/app.js",
main: "./src/js/main.js"
}
複製代碼
通常入口文件中可能是 import 或者 require 等模塊導入命令。
output 顧名思義,Webpack打包後文件的具體配置 經常使用的屬性有 4 個
path: ${__dirname }/dist
打包後文件所在路徑
filename: "js/[name].js"
打包後文件的名字,這裏有 4 種經常使用的寫法
自定義
[name].js
表明的即是入口的文件名
[hash].js
這次打包後的hash值
[chunkhash]
該塊打包後的hash值
publicPath: "http://cdn.com/"
上線時的公共路徑,主要應用於線上
chunkFilename: 'js/[name].js'
按需加載模塊時輸出的文件名稱
Loader 是 Webpack 中最振奮人心的東西了!
將一切瀏覽器不支持的語言,處理成 瀏覽器能夠支持。 針對各個文件類型,都有各類的 Loader 等你去挖掘。
Loader 的工做方式 是從右向左執行,鏈式地按照順序進行編譯。 loader 鏈中的第一個返回值給下一個 loader,在最後一個 loader,返回所預期的結果。
loader 能夠是同步或異步函數,也可以使用 options 對象去接受配置參數。
基礎結構
module:{
rules:[
{
test:/\.xxx$/,//以xxx結尾的文件
loader: "xxx-loader",
exclude: {排除的路徑},
include: {包含的路徑},
options: {Loader配置}
}
]
}
複製代碼
能夠很清楚的看到,Loader 利用 test 的正則 找到各個類型文件,而後使用 loader 進行處理,即可轉換成瀏覽器支持的文件。
其中我知道的 loader 的寫法有兩種:
loaders:[
{loader:"style-loader"},
{ loader: "css-loader?modules", options: { importLoaders: 1 } },
{loader: "less-loader"}
]
複製代碼
loader: "style-loader!css-loader?importLoaders=1!less-loader"
複製代碼
下面介紹三個 前端必備的 Loader 方式
style-loader
經過注入<style>
標籤將 CSS 添加到 DOM
npm install style-loader --save-dev
複製代碼
css-loader
css-loader像import / require()同樣解釋@import和url()並解析它們。
npm install css-loader --save-dev
複製代碼
postcss-loader
補充 不兼容的css屬性 的瀏覽器前綴
npm install post-loader --save-dev
複製代碼
less-loader
將Less 轉換成 CSS
npm install less --save-dev
npm install less-loader --save-dev
複製代碼
babel
主要用於將 es6 轉換成 es2015
複製代碼
npm install --save-dev babel-core babel-loader babel-preset-es2015
複製代碼
file-loader
用於壓縮文件
npm install --save-dev file-loader
複製代碼
url-loader
若是文件下於 規定限制,將會轉換成 二進制編碼
npm install --save-dev url-loader
複製代碼
另外 我想介紹一下 本身經常使用的 ejs-loader
npm install --save-dev ejs-loader
複製代碼
test:/\.ejs$/ , loader:"ejs-loader",
複製代碼
<div class="layer">
<div><%= name %></div>
<% for(let i = 0; i < Array.length;++i) { %>
<%= Array[i] %>
<% } %>
</div>
複製代碼
//入口文件
import tpl from "./layer.ejs";
document.body.innerHTML = tpl({
name:"Simon",
arr:["Apple","Xiaomi"]
});
複製代碼
運行 生成後的頁面 ,便會發現 ejs 組件已經被加進去了, 想象一下,咱們在平時工做中是否能夠把 一個輪播圖,或者 排行榜 、評論 當成一個組件呢?
plugins
在平常工做中,咱們使用 Loader 處理不一樣類型的文件,當有某種其餘方面的需求時,好比 抽離 CSS 、生成多頁面 HTML ,plugins 便派上了用場。
插件的使用,通常都要先 require 出來,而後在 plugins 屬性中 進行初始化
const htmlWebpackPlugin = require("html-webpack-plugin");
......
plugins: [ new htmlWebpackPlugin({/* options */}) ]
複製代碼
下面將介紹 一些工做中經常使用的插件
clean-webpack-plugin
主要用於 打包以前 先清空 打包目錄下的文件,防止文件混亂。
npm install --save-dev clean-webpack-plugin
複製代碼
html-webpack-plugin
主要用於生成HTML,能夠規定 模板HTML,也能夠爲 模板傳入參數,壓縮文件等
npm install --save-dev html-webpack-plugin
複製代碼
這個插件可謂是 前端必備的,它的配置有不少
new htmlWebpackPlugin({
//打包後的文件名
filename: "index.html",
//模板
template: "index.html",
//爲true自動生成script標籤添加到html中
//或者寫 body/head 標籤名
inject: false,//js的注入標籤
//經過<%= htmlWebpackPlugin.options.title %>引用
title: "參數title",
//經過<%= htmlWebpackPlugin.options.date %> 引用
date: new Date()
//網站的圖標
favicon: 'path/to/yourfile.ico'
//生成這次打包的hash
//若是文件名中有哈希,便表明有 合理的緩衝
hash: true,
//排除的塊
excludeChunks: [''],
//選中的塊 與入口文件相關
chunks: ['app','people'],
//壓縮
minify:{
removeComments: true,collapseWhitespace: true,
minifyJS: true, minifyCSS: true,minifyURLs: true,
}
}),
複製代碼
那麼問題來了,咱們在模板文件中 又該怎樣使用參數呢? 直接按照 ejs 的語法寫入 html 文件便可!
<!DOCTYPE html>
<html lang="en">
<%= htmlWeb packPlugin.options.date %>
</html>
複製代碼
生成後的模板文件
<!DOCTYPE html>
<html lang="en">
Thu Dec 07 2017 10:01:58 GMT+0800 (中國標準時間)
</html>
複製代碼
另外,若是想生成 多頁面應用,只需 將上面的配置,多複製幾遍便可。
new htmlWebpackPlugin({ filename: "index1.html", }
new htmlWebpackPlugin({ filename: "index2.html", }
new htmlWebpackPlugin({ filename: "index3.html", }
複製代碼
UglifyJsPlugin
主要用於壓縮 Javascript 文件
npm i -D uglifyjs-webpack-plugin
複製代碼
webpack.ProvidePlugin
自動加載模塊,全局使用變量,下面藉助 官網的DEMO
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
// in a module
$('#item'); // <= 起做用
jQuery('#item'); // <= 起做用
// $ 自動被設置爲 "jquery" 輸出的內容
複製代碼
open-browser-webpack-plugin
打開服務器後 會自動打開瀏覽器端口,用起來 很方便
HotModuleReplacementPlugin
熱更新插件
webpack
最基本的啓動webpack命令
webpack -w
監控代碼變化,實時進行打包更新
webpack -p
對打包後的文件進行壓縮,利用線上發佈
webpack -d
提供SourceMaps,方便調試代碼
webpack --colors
輸出結果帶彩色,能夠更詳細的查看信息
webpack --profile
輸出性能數據,能夠看到每一步的耗時
不知道你如今時候有沒有一個想法? webpack 打包後的文件就必定正確無誤嗎? 若是發生錯誤的話,該怎麼辦呢?
devtool 屬性 便提供了生成 sourcemap 的功能,具體有下面這些選項。
source-map
此選項具備最完備的source map,但會減慢打包的速度;
cheap-module-source-map
生成一個不帶列映射的map
eval-source-map
使用eval打包源文件模塊,生成一個完整的source map。
cheap-module-eval-source-map
這是最快生成source map的方法,生成後的Source Map 會和打包後的 JavaScript 文件同行顯示,但沒有列映射,因此慎用
contentBase: "./dist",
本地服務器所加載的頁面所在的目錄
historyApiFallback: true,
再找不到文件的時候默認指向index.html
inline: true,
當源文件改變時會自動刷新頁面
hot: true,
熱加載開啓
port:8080
設置默認監聽端口
extensions: [".js", ".html", ".css", ".txt","less","ejs","json"],
自動擴展文件後綴名,意味着咱們require模塊能夠省略不寫後綴名
alias: { Temp: path.resolve(__dirname, "src/templates/") }
模塊別名定義,直接 require('AppStore') 便可,方便後續直接引用別名
經常使用於字符串拼接路徑。
const path = require("path");
複製代碼
有兩個 API
path.resolve()
將相對路徑轉換成絕對路徑
const aPath = path.resolve("__dirname","js","main.js");
// aPath = 當前目錄下的 js 文件夾的 main.js 文件的路徑
複製代碼
path.join()
對路徑進行拼接
const rPath = path.join("source","js","main.js");
// aPath = //source/js/main.js
複製代碼
上面咱們已經提過了 webpack -w
命令,它能夠實時的監控 代碼的改變,從而自動進行打包,可是 有個缺點 在於它不能及時的刷新界面。
在咱們 開啓服務器後,是沒法使用 此命令的,這個時候,若是你還想進行 自動打包,又想自動刷新界面,熱更新 即是不二之選,另外 Webpack 只會熱更新 發生改變的模塊,不會從新加載整個頁面,即可加快開發速度。
開啓步驟:
devServer: {
hot: true,//熱加載開啓
inline: true,//文件改變時會自動刷新頁面
}
複製代碼
const webpack = require("webpack");
//Other property
plugins: [
new webpack.HotModuleReplacementPlugin()
]
複製代碼
另外,只有修改 依賴的項目,纔會進行實時更新。
如今是一個 Web 技術蓬髮的時代,必定要把握住時代潮流。
在寫這篇文章前,我已經花了一成天的時間,把工做所須要 幾乎全部的 Loader , plugins 收集了一遍,專門寫了個源文件。但由於個人源文件太大 必須可顯示,可隱藏,否則影響閱讀 ,可掘金的 Markdown 不支持自定義樣式 ,因此我貼在了個人博客,但願它能對你有幫助。
最後,再送你個福利,若是你是 我的博客愛好者,我最近新開發了一款美觀開源的主題,期待你的使用!