參考:http://www.javashuo.com/article/p-gqgzutje-er.htmlcss
1.什麼是webpack,爲何要使用它html
一些優秀的網站每每有許多JavaScript文件,不少依賴項,爲了簡化開發的複雜度,前端有不少實踐方法:前端
這些方法每每有不少文件瀏覽器不能直接識別,須要二次處理後才能夠,此時webpack應允而生node
WebPack能夠看作是模塊打包機:react
它作的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其轉換和打包爲合適的格式供瀏覽器使用webpack
Webpack的工做方式是:es6
把你的項目當作一個總體,經過一個給定的主文件(如:index.js),Webpack將從這個文件開始找到你的項目的全部依賴文件,使用loaders處理它們,最後打包爲一個(或多個)瀏覽器可識別的JavaScript文件web
2.開始使用webpack正則表達式
2.1 開始安裝webpacknpm
Webpack可使用npm安裝,新建一個空的練習文件夾(此處命名爲webpack sample project),在終端中轉到該文件夾後執行下述指令就能夠完成安裝
//全局安裝 npm install -g webpack //安裝到你的項目目錄 npm install --save-dev webpack
2.2 開始前準備
2.2.1 在這個路徑的cmd中輸入npm init,自動生成package.json文件寫入項目的信息,若是不作正式使用能夠回車默認便可
2.2.2 在本項目中安裝Webpack做爲依賴包
// 安裝Webpack npm install --save-dev webpack
2.2.3 回到以前的空文件夾,並在裏面建立兩個文件夾,app文件夾和public文件夾,app文件夾用來存放原始數據和咱們將寫的JavaScript模塊,public文件夾用來存放以後供瀏覽器讀取的文件(包括使用webpack打包生成的js文件以及一個index.html
文件)。接下來咱們再建立三個文件:
index.html
--放在public文件夾中;Greeter.js
-- 放在app文件夾中;main.js
-- 放在app文件夾中;
在index.html文件中寫入最基礎的html代碼,它在這裏目的在於引入打包後的js文件(這裏咱們先把以後打包後的js文件命名爲bundle.js
,以後咱們還會詳細講述)
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Webpack Sample Project</title> </head> <body> <div id='root'> </div> <script src="bundle.js"></script> </body> </html>
咱們在Greeter.js
中定義一個返回包含問候信息的html
元素的函數,並依據CommonJS規範導出這個函數爲一個模塊:
// Greeter.js module.exports = function() { var greet = document.createElement('div'); greet.textContent = "Hi there and greetings!"; return greet; };
main.js
文件中咱們寫入下述代碼,用以把Greeter模塊
返回的節點插入頁面。
//main.js const greeter = require('./Greeter.js'); document.querySelector("#root").appendChild(greeter());
2.2.4 正式使用webpack
webpack能夠在終端中使用,在基本的使用方法以下:
# {extry file}出填寫入口文件的路徑,本文中就是上述main.js的路徑, # {destination for bundled file}處填寫打包文件的存放路徑 # 填寫路徑的時候不用添加{} webpack {entry file} {destination for bundled file}
指定入口文件後,webpack將自動識別項目所依賴的其它文件,不過須要注意的是若是你的webpack不是全局安裝的,那麼當你在終端中使用此命令時,須要額外指定其在node_modules中的地址,繼續上面的例子,在終端中輸入以下命令
# webpack非全局安裝的狀況 node_modules/.bin/webpack app/main.js public/bundle.js
運行完成後就會在public文件夾中自動生成bundle.js,被index.html引用成功!至此一個完整的小webpack項目結束
有沒有以爲在cmd中輸入的webpack命名比較繁瑣,好的,這裏有較爲簡單的命令方法,但須要修改下配置文件package.json
{ "name": "webpack-sample-project", "version": "1.0.0", "description": "Sample webpack project", "scripts": { "start": "webpack" // 修改的是這裏,JSON文件不支持註釋,引用時請清除 }, "author": "zhang", "license": "ISC", "devDependencies": { "webpack": "3.10.0" } }
以後想要啓動啓動webpack只需在對應的項目目錄下只需npm start效果就能完整的命令效果同樣
3.webpack 強大功能
3.1 可調試
通常經過打包後的文件,不容易找到出錯的地方,對應你寫的代碼的位置,配置了Source maps就能幫咱們解決這個問題,經過簡單的配置,webpack能夠幫咱們生成Source Maps,這爲咱們提供了一種對應的編譯文件與源文件方法,使得編譯後的代碼可讀性更高:配置devtool便可
devtool選項 | 配置結果 |
---|---|
source-map |
在一個單獨的文件中產生一個完整且功能徹底的文件。這個文件具備最好的source map ,可是它會減慢打包速度; |
cheap-module-source-map |
在一個單獨的文件中生成一個不帶列映射的map ,不帶列映射提升了打包速度,可是也使得瀏覽器開發者工具只能對應到具體的行,不能對應到具體的列(符號),會對調試形成不便; |
eval-source-map |
使用eval 打包源文件模塊,在同一個文件中生成乾淨的完整的source map 。這個選項能夠在不影響構建速度的前提下生成完整的sourcemap ,可是對打包後輸出的JS文件的執行具備性能和安全的隱患。在開發階段這是一個很是好的選項,在生產階段則必定不要啓用這個選項; |
cheap-module-eval-source-map |
這是在打包文件時最快的生成source map 的方法,生成的Source Map 會和打包後的JavaScript 文件同行顯示,沒有列映射,和eval-source-map 選項具備類似的缺點; |
對小到中型的項目中,eval-source-map
是一個很好的選項,再次強調你只應該開發階段使用它,咱們繼續對上文新建的webpack.config.js
,進行以下配置:
module.exports = { devtool: 'eval-source-map', entry: __dirname + "/app/main.js", output: { path: __dirname + "/public", filename: "bundle.js" } }
方法構建速度更快,可是不利於調試,推薦在大型項目考慮時間成本時使用。
cheap-module-eval-source-map
3.2 配置本地服務器
這個本地服務器是基於node.js,須要將webpack-dev-server在項目根目錄下安裝
npm install --save-dev webpack-dev-server
devserver做爲webpack配置選項中的一項,如下是它的一些配置選項,更多配置可參考這裏
devserver的配置選項 | 功能描述 |
---|---|
contentBase | 默認webpack-dev-server會爲根文件夾提供本地服務器,若是想爲另一個目錄下的文件提供本地服務器,應該在這裏設置其所在目錄(本例設置到「public"目錄) |
port | 設置默認監聽端口,若是省略,默認爲」8080「 |
inline | 設置爲true ,當源文件改變時會自動刷新頁面 |
historyApiFallback | 在開發單頁應用時很是有用,它依賴於HTML5 history API,若是設置爲true ,全部的跳轉將指向index.html |
把這些命令加到webpack的配置文件中,如今的配置文件webpack.config.js
以下所示
module.exports = { devtool: 'eval-source-map', entry: __dirname + "/app/main.js", output: { path: __dirname + "/public", filename: "bundle.js" }, devServer: { contentBase: "./public",//本地服務器所加載的頁面所在的目錄 historyApiFallback: true,//不跳轉 inline: true//實時刷新 } }
在package.json
中的scripts
對象中添加以下命令,用以開啓本地服務器:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack", "server": "webpack-dev-server --open" },
在終端中輸入npm run server
便可在本地的8080
端口查看結果
3.3 Loaders
Loaders的功能就強大了,他能夠將不是js的文件類型轉爲js讓瀏覽器能夠識別
好比說分析轉換scss爲css,或者把下一代的JS文件(ES6,ES7)轉換爲現代瀏覽器兼容的JS文件,對React的開發而言,合適的Loaders能夠把React的中用到的JSX文件轉換爲JS文件
Loaders須要單獨安裝而且須要在webpack.config.js
中的modules
關鍵字下進行配置,Loaders的配置包括如下幾方面:
test
:一個用以匹配loaders所處理文件的拓展名的正則表達式(必須)loader
:loader的名稱(必須)include/exclude
:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選);query
:爲loaders提供額外的設置選項(可選) 不過在配置loader以前,咱們把Greeter.js
裏的問候消息放在一個單獨的JSON文件裏,並經過合適的配置使Greeter.js
能夠讀取該JSON文件的值,各文件修改後的代碼以下:
在app文件夾中建立帶有問候信息的JSON文件(命名爲config.json
)
{ "greetText": "Hi there and greetings from JSON!" }
更新後的Greeter.js
var config = require('./config.json'); module.exports = function() { var greet = document.createElement('div'); greet.textContent = config.greetText; return greet; };
在看如何具體使用loader以前咱們先看看Babel是什麼?
Babel實際上是一個編譯JavaScript的平臺,它能夠編譯代碼幫你達到如下目的:
Babel實際上是幾個模塊化的包,其核心功能位於稱爲babel-core
的npm包中,webpack能夠把其不一樣的包整合在一塊兒使用,對於每個你須要的功能或拓展,你都須要安裝單獨的包(用得最多的是解析Es6的babel-env-preset
包和解析JSX的babel-preset-react
包)。
// npm一次性安裝多個依賴模塊,模塊之間用空格隔開 npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
在webpack
中配置Babel的方法以下:
module.exports = { entry: __dirname + "/app/main.js",//已屢次說起的惟一入口文件 output: { path: __dirname + "/public",//打包後的文件存放的地方 filename: "bundle.js"//打包後輸出文件的文件名 }, devtool: 'eval-source-map', devServer: { contentBase: "./public",//本地服務器所加載的頁面所在的目錄 historyApiFallback: true,//不跳轉 inline: true//實時刷新 }, module: { rules: [ { test: /(\.jsx|\.js)$/, use: { loader: "babel-loader", options: { presets: [ "env", "react" ] } }, exclude: /node_modules/ } ] } };
如今你的webpack的配置已經容許你使用ES6以及JSX的語法了。繼續用上面的例子進行測試,不過此次咱們會使用React,記得先安裝 React 和 React-DOM
npm install --save react react-dom
接下來咱們使用ES6的語法,更新Greeter.js
並返回一個React組件
//Greeter,js import React, {Component} from 'react' import config from './config.json'; class Greeter extends Component{ render() { return ( <div> {config.greetText} </div> ); } } export default Greeter
修改main.js
以下,使用ES6的模塊定義和渲染Greeter模塊
// main.js import React from 'react'; import {render} from 'react-dom'; import Greeter from './Greeter'; render(<Greeter />, document.getElementById('root'));
從新使用npm start
打包,若是以前打開的本地服務器沒有關閉,你應該能夠在localhost:8080
下看到與以前同樣的內容,這說明react
和es6
被正常打包了。
Babel其實能夠徹底在 webpack.config.js
中進行配置,可是考慮到babel具備很是多的配置選項,在單一的webpack.config.js
文件中進行配置每每使得這個文件顯得太複雜,所以一些開發者支持把babel的配置選項放在一個單獨的名爲 ".babelrc" 的配置文件中。咱們如今的babel的配置並不算複雜,不過以後咱們會再加一些東西,所以如今咱們就提取出相關部分,分兩個配置文件進行配置(webpack會自動調用.babelrc
裏的babel配置選項),以下:
module.exports = { entry: __dirname + "/app/main.js",//已屢次說起的惟一入口文件 output: { path: __dirname + "/public",//打包後的文件存放的地方 filename: "bundle.js"//打包後輸出文件的文件名 }, devtool: 'eval-source-map', devServer: { contentBase: "./public",//本地服務器所加載的頁面所在的目錄 historyApiFallback: true,//不跳轉 inline: true//實時刷新 }, module: { rules: [ { test: /(\.jsx|\.js)$/, use: { loader: "babel-loader" }, exclude: /node_modules/ } ] } };
//.babelrc { "presets": ["react", "env"] }
到目前爲止,咱們已經知道了,對於模塊,Webpack能提供很是強大的處理功能,那那些是模塊呢。
Webpack有一個不可不說的優勢,它把全部的文件都都當作模塊處理,JavaScript代碼,CSS和fonts以及圖片等等經過合適的loader均可以被處理。
webpack提供兩個工具處理樣式表,css-loader
和 style-loader
,兩者處理的任務不一樣,css-loader
使你可以使用相似@import
和 url(...)
的方法實現 require()
的功能,style-loader
將全部的計算後的樣式加入頁面中,兩者組合在一塊兒使你可以把樣式表嵌入webpack打包後的JS文件中。
//安裝 npm install --save-dev style-loader css-loader
//使用 module.exports = { ... module: { rules: [ { test: /(\.jsx|\.js)$/, use: { loader: "babel-loader" }, exclude: /node_modules/ }, { test: /\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader" } ] } ] } };
接下來,在app文件夾裏建立一個名字爲"main.css"的文件,對一些元素設置樣式
/* main.css */ html { box-sizing: border-box; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } *, *:before, *:after { box-sizing: inherit; } body { margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } h1, h2, h3, h4, h5, h6, p, ul { margin: 0; padding: 0; }
咱們這裏例子中用到的webpack
只有單一的入口,其它的模塊須要經過 import
, require
, url
等與入口文件創建其關聯,爲了讓webpack能找到」main.css「文件,咱們把它導入」main.js 「中,以下
//main.js import React from 'react'; import {render} from 'react-dom'; import Greeter from './Greeter'; import './main.css';//使用require導入css文件 render(<Greeter />, document.getElementById('root'));
上面的代碼說明webpack是怎麼把css當作模塊看待的,我們繼續看一個更加真實的css模塊實踐。