demo地址:https://github.com/yonglijia/...javascript
首先來介紹下webpack是幹嗎的。 css
webpack簡單的來說,是一個前端模塊化管理和打包工具,能夠將你的文件所依賴的js,css,node包等所有打包成一個bundle文件,而且可以處理各類模塊之間依賴問題。在webpack的世界裏,一切皆模塊!但它又不只僅是一個打包工具。它不只可以輕鬆處理你項目中的依賴關係和加載順序,還能讓這個流程更加智能化,自動化。html
webpack的使用,最複雜的一部分是莫過於它的配置項。webpack經過你的配置項,放置全部與打包相關的信息。一個基本的配置包括前端
module.exports = { entry: '', output: {}, module: { rules: [] }, plugins: [], };
咱們能夠這樣理解這幾個配置:java
你若是要打包一個文件,那首先要指定文件的地址,也就是entry;打包以後放在那裏呢,也就是output;打包過程當中文件要通過怎麼樣的處理,也就是rules中的loader;如何可以使webpack打包更快,體積更小呢,也就是plugins。這些配置相輔相成,緊密結合node
這些配置命名須要寫入webpack.config.js中。在項目中,執行webpack
,就會自動引用這個文件。react
下面咱們詳細介紹下這些配置。創建一個簡單的項目,包含webpack
testWebpck.jsgit
module.exports = function() { var testDiv = document.createElement('div'); testDiv.textContent = "hello world"; return testDiv; };
index.jsgithub
var testWebpack = require('./testWebpack.js'); document.querySelector("#root").appendChild(testWebpack());
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>learn webpack</title> </head> <body> <div id="root"> </div> <script src="build/bundle.js"></script> </body> </html>
webpack.config.js
module.exports = { entry: __dirname+"/app/index.js",//打包的js output: { path: __dirname + "/build",//打包後的文件存放的地方 filename: "bundle.js",//打包後bundle文件的文件名 }, module: { rules: [] }, plugins: [], };
咱們在項目根目錄中,執行webpack
,
瀏覽器打開index.html,能夠看到hello world!
。修改testWebpck, 修改成「hello webpack!」,從新執行webpack,再次打開index.html,能夠看到瀏覽器中變爲hello webpack!
咱們可使用webpack-dev-server,來構建一個本地服務器,經過這個服務器,監聽你的代碼,實時更新你修改的內容。
首先
npm install webpack-dev-server
而後在package.json中添加腳本
"scripts": { "start": "webpack-dev-server --config webpack.config.js", },
npm的
start
命令是一個特殊的腳本,直接使用npm start
就能夠執行其對於的命令;而若是不是start
,想要在命令行中運行時,須要這樣用npm run {script name}
如npm run build
執行npm start
,在瀏覽器中輸入http://127.0.0.1:8080
,能夠看到咱們所看到的如出一轍的頁面。
Webpac-dev-server須要添加devServer配置
devServer{ hot:true,// inline:true,// port:8080,//默認8080 proxy:{//接口代理 '/xxx/**': {//接口匹配的地址 target:"代理地址", secure: false }, } }
目前爲止,咱們已經使用wepack成功完成了一個文件的打包,而且能在開發環境中使用。可是未使用任何的loader,plugin,由於這裏面涉及到的文件還太少,種類也很少。下面來一步步豐富這個小項目,引入所須要的配置。
咱們在項目中引入css
index.css
#root{ border:1px solid red; }
在index.js中引入require('./index.css');
執行npm start
,
這時已經報錯,提示咱們要引入相應的loader來處理css。是時候展現真正的技術了——— loader。
loader是什麼呢?正如咱們上面所講的是,它用來如何處理咱們的打包文件的;如今若是不引入loader,那就沒法處理css文件。loader不只僅是處理css,還能夠用來css的預處理、js的中使用ES6等高級語法處理成瀏覽器能兼容的格式。文件、圖片、json等處理,都須要用到loader;通過loader的處理,這些文件可以很好的打入打包後的bundle中。
一個loader所須要的配置包括四個方面
test、loader、includer/exclude、query
首先來看個示範
{ test: /\.js$|\.jsx$/, loader: 'babel-loader', exclude: /(node_modules|bower_components)/, query: { presets: ['es2015', 'react'], plugins: ['transform-class-properties', 'lodash'] }, },
test是一個正則表達式,它用來匹配適用於loader文件的擴展名
loader中是loader的名稱,1.x版本不須要加上「-loader」,日後的版本須要加上「-loader」.
這兩個都是必須添加的配置,下面兩個是可選的。
include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)
query:爲loaders提供額外的設置
那咱們來根據上面的配置來設置loader,來處理css。
webpack提供兩個工具處理樣式表,css-loader 和 style-loader;安裝這兩個npm包,修改咱們的配置
module.exports = { entry: __dirname+"/app/index.js",//打包的js output: { path: __dirname + "/build",//打包後的文件存放的地方 filename: "bundle.js",//打包後bundle文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]},]//引入多個loader,loader要寫成loaders,屬性爲一個數組,存放各個loader }, plugins: [], };
執行npm start
,在瀏覽器中咱們發現,helllo world中已經添加上了紅色的邊框了。
css-loader使你可以使用相似@import和url(...)的方法實現require的功能,style-loader將全部的計算後的樣式加入頁面中,兩者組合在一塊兒使你可以把樣式表嵌入webpack打包後的js文件中
有一點要注意的是:loader是有順序的。webpack確定是先將全部css模塊依賴解析完獲得計算結果再建立style標籤。所以應該把style-loader放在css-loader的前面(webpack loader的執行順序是從右到左),順序不對,會報錯。
這樣咱們基本上使用了完成了一個loader的基本配置。
咱們來配置下添加其餘loader的配置項:
處理圖片
須要同時安裝url-loader和file-loader
{test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'},
url-loader與file-loader的工做方式類似,若是文件的體積比byte limit小,就能返回Data Url。若是圖片比limit小,將直接以base64的形式內聯在代碼中。若是圖片比limit(以bytes爲單位)大,那麼webpack就會使用file-loader去處理文件,而且全部的查詢參數都會傳遞給file-loader。
咱們想把js和圖片打包成不一樣的文件夾,須要把output配置項修改一下
output: { path: __dirname + "/build",//打包後的文件存放的地方 filename: "js/bundle.js",//打包後bundle文件的文件名 },
在項目app文件夾中分別添加兩個圖片,一個大於1024,一個小於1024,circle_loaction.png,data_update.gif
添加上面的配置,執行weibpack,發現一個有一個文件在build/images中生成。
這裏面有一個路徑的點須要注意:
若是在output中添加publicPath,好比說/xxx/
module.exports = { entry: __dirname+"/app/index.js",//打包的js output: { publicPath: '/xxx/', path: __dirname + "/build",//打包後的文件存放的地方 filename: "bundle.js",//打包後bundle文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]}, {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'}, ] }, plugins: [], };
那咱們訪問http://127.0.0.1:8080
,發現bundle找不到。這是由於加上publicPath以後,訪問內存中的文件bundle都須要加上/xxx/
(但實際上引用的是內存中的文件,既不是/build/js/也不是/xxx/)。因此要修改html中的引用地址方能使用。
<script src="xxx/js/bundle.js"></script>
publicPath表示資源的發佈地址,加上該屬性後,打包文件中全部經過相對路徑引用的資源都會被配置的路徑所替換。
若是此時修改index.css
#root{ border:1px solid red; height: 350px; background-image:url("./data_update.gif"); }
./data_update.gif 就會自動替換成xxx/images/data_update-37a1914078.gif。
path和publicPath的區別
path:/build/js
publicPaht:/online/
線下環境
path是打包後文件存放的路徑,不能用於html中的js引用
publicPath表示的是資源發佈的路徑。自動指向path編譯目錄(/online/ => /build/js/),html中引用js文件時,必須引用此虛擬路徑。
線上環境
webpack進行編譯(固然是編譯到/build/js/),咱們須要把目錄(/build/js/)下的文件,所有複製到/online/目錄下(注意:不是去修改index.html中引用bundle.js的路徑)
處理jsx文件
webpack不能直接處理jsx,須要藉助於babel.
babel堪稱神器,被譽爲下一代 JavaScript 語法的編譯器。用它,你能夠不用等瀏覽器的支持,就可使用最新的標準的語法。使用它能夠解析jsx的語法。對於babel,不作過多介紹。
首先安裝
npm install --save-dev babel-cli babel-preset-env babel-core babel-loader babel-preset-es2015 babel-preset-react react react-dom
建立 .babelrc
{ "presets": ["react","es2015"] }
添加loader
{ test: /\.js$|\.jsx$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', }
修改index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>learn webpack</title> </head> <body> <div id="root"> </div> <div id="react"> </div> <script src="build/js/index.js"></script> <script src="build/js/testReact.js"></script> </body> </html>
添加testWebpack.jsx,
import React from 'react'; import ReactDOM from 'react-dom'; class TestReact extends React.Component{ constructor(props){ super(props); } render(){ return <div>this is a react div <img src={require('./data_update.gif')}/> </div> } } ReactDOM.render(<TestReact/>,document.getElementById('react'))
修改配置
module.exports = { entry: { index :__dirname+"/app/index.js", testReact:__dirname+"/app/testReact.jsx", }, output: { path: __dirname + "/build",//打包後的文件存放的地方 filename: "js/[name].js"//打包後輸出文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]}, {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'}, { test: /\.js$|\.jsx$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', } ] }, plugins: [], };
這裏咱們設置了兩個入口文件,而且打包成不一樣的js,這個js的名字和他們自己的js的名字相同,經過filename: "js/[name].js"
指定。
這樣設置完咱們就完成了使用babel-loader處理jsx文件。
稍微展開一點entry:
entry 有三種類型字符串,數組和對象
entry:"xxx/index.js",
entry:["xxx/index.js","xxx/index2.js"],
entry:{
index:"xxx/index.js",
index2:"xxx/index2.js"
},
下面咱們介紹下,如何添加插件,使咱們的打包工程更快,更智能。
先介紹下一些經常使用的插件。
uglifyjs-webpack-plugin :JS壓縮
var webpack = require('webpack'); var UglifyJSPlugin = require('uglifyjs-webpack-plugin') module.exports = { entry: { index :__dirname+"/app/index.js", testReact:__dirname+"/app/testReact.jsx", }, output: { path: __dirname + "/build",//打包後的文件存放的地方 filename: "js/[name].js"//打包後輸出文件的文件名 }, module: { rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]}, {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'}, { test: /\.js$|\.jsx$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', } ] }, plugins: [ new UglifyJSPlugin(), ], };
咱們這時候打開build/js中的js文件,發現裏面都被壓縮混淆了。
DefinePlugin:定義全局變量
Hot Module Replacement:
在webpack中實現HMR很簡單,只須要兩個配置
添加new webpack.HotModuleReplacementPlugin()
修改腳本 "start": "webpack-dev-server --config webpack.config.js"
,
插件分爲內置和外置的,不過用法都是大同小異的。不一樣的插件,配置參數也不同。
devtool:這個是用來配置soucemap的類型,在開發的時候調試特別有用。裏面的配置特別多,後面會單獨介紹這個地方。
resolve:配置短路徑引用
resolve: { alias: { module: path.resolve(APP_PATH, 'module'), component: path.resolve(APP_PATH, "component"), service: path.resolve(APP_PATH, "service"), page: path.resolve(APP_PATH, "page"), node_modules: path.resolve(ROOT_PATH, 'node_modules') }, extensions: ['.js', '.jsx', '.json', '.scss'] },
使用這個選項的話,你能夠直接使用好比require('page/index')
,其實就是path.resolve(APP_PATH, "page")+'/index'
,extensions是用來匹配所要引用的文件類型,匹配以index開頭的 ['.js', '.jsx', '.json', '.scss']
文件,若是沒有,就會報錯。
這篇文章權當個入門文檔,裏面還有不少須要一一深刻挖掘的,好比devtool到底選擇哪一個最好,怎麼使項目的打包更快,怎麼使用dll等等,後續會一點一點的寫。