什么是webpack
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
戈德斯文版譯文:webpack是一個模塊打包器。它的主要目的是將JavaScript文件打包以便在瀏覽器中使用,并且它也能夠轉(zhuǎn)換查排、打包或構(gòu)建任何資源或數(shù)據(jù)虐杯。
webpack的宗旨就是把所用用的JavaScript還是css唱较,或者是圖片晾蜘,甚至各類預(yù)編譯器、js的超集語言鼓鲁,都直接打包成最純粹的js邮辽、css唠雕、jpg和png。 在前端工程化吨述,自動化的路上插了好多路燈岩睁。
Webpack與Gulp、Grunt區(qū)別
Gulp和Grunt的工作方式是在一個配置文件中寫好對某一類文件進(jìn)行某種或幾種操作揣云,然后可以自動幫你轉(zhuǎn)換捕儒、壓縮等一系列操作,在自動化有一定的幫助。
而webpack則是在自動化處理各類文件刘莹、資源上以后阎毅,會把整個項目當(dāng)成一個整體,從一個入口文件点弯,把所有依賴到的資源都進(jìn)行整合處理扇调,打包。使用webpack抢肛,能真正體會到JavaScript的發(fā)展方向——模塊化狼钮。提高了開發(fā)效率,降低了維護(hù)成本捡絮。
初始化項目
$ mkdir webpack-demo
$ cd webpack-demo
$ npm init
如沒有特殊需求熬芜,一路回車就完事了,生成package.json的文件锦援。
安裝webpack
$ npm install -g webpack webpack-cli
$ npm install webpack --save-dev
構(gòu)建項目目錄
在項目跟目錄下執(zhí)行
$ mkdir src // 創(chuàng)建源代碼目錄
$ mkdir public // 創(chuàng)建公共模板目錄
$ cd src // 進(jìn)入源代碼目錄
$ mkdir components // 創(chuàng)建組件目錄
$ touch index.js // 創(chuàng)建項目入口文件
$ touch App.js // 創(chuàng)建App組件
$ cd ../public // 回到項目跟目錄猛蔽,進(jìn)入公共模板目錄
$ touch index.html // 創(chuàng)建公共模板文件
$ cd .. // 返回跟目錄
$ mkdir dev // 創(chuàng)建開發(fā)目錄
$ mkdir dist // 創(chuàng)建生產(chǎn)目錄
$ touch webpack.config.dev.js // 創(chuàng)建開發(fā)環(huán)境webpack配置文件
$ touch webpack.config.prod.js // 創(chuàng)建生產(chǎn)環(huán)境webpack配置文件
最后的目錄結(jié)構(gòu)
webpack配置
寫入最基本的webpack
webpack.config.dev.js
const path = require('path');
module.exports = {
/* 輸入配置 */
entry: {
app: './src/index.js' /* 設(shè)置項目入口路徑 */
},
mode: 'development', /* 配置打包環(huán)境為開發(fā)環(huán)境 */
/* 輸出配置 */
output: {
path: path.resolve(__dirname, './dev'), /* 配置輸出路徑 */
filename: 'bundle.min.js', /* 配置輸出名稱 */
},
};
為了更方便的在命令行中執(zhí)行webpack打包命令剥悟,我們在package.json寫上
{
"scripts": {
"start": "webpack --config webpack.config.dev.js"
}
}
這樣在命令行中輸入npm run start
就可以執(zhí)行根據(jù)webpack.config.dev.js的webpack打包過程了灵寺。
如果想要動態(tài)監(jiān)聽文件變化需要在命令后面添加 --watch。
引入react
安裝react
$ npm install react react-dom
安裝好以后在./src/index.js
寫上
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDom.render(<App />, document.getElementById('root'));
然后在./src/App.js
中寫
import React from 'react';
import './App.less';
const App = () => (
<div>首頁</div>
);
export default App;
因為只是demo区岗,沒有寫任何方法和生命周期函數(shù)略板,所以寫的無狀態(tài)組件
最后在./public/index.html
寫上模板,主要是寫一個id為root的div
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpack react</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
loader
webpack單單自己是不能對各種資源進(jìn)行處理的慈缔,所以要借用各種loader來進(jìn)行資源處理
css-loader叮称、style-loader和less-loader
我們先來配置處理css文件的loader,直接加上處理預(yù)編譯器less的loader
首先藐鹤,安裝各種這三個loader瓤檐,并且安裝less,如果你使用的sass或者stylus娱节,可以安裝對應(yīng)的預(yù)編譯器和loader
$ npm install less less-loader css-loader style-loader --save-dev
安裝完以后進(jìn)行在webpack.config.dev.js
中用上他們
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.(css|less)$/,
use: ['style-loader', 'css-loader', 'less-loader'],
include: path.resolve('./src'),
},
]
}
...
};
這樣就不會有問題了挠蛉,注意!肄满!loader的順序一定不要搞錯谴古,因為loader是按從最后一個往前處理的,先用less-loader處理稠歉,最后用style-loader處理掰担。
url-loader
處理靜態(tài)文件,安裝
$ npm install url-loader
配置webpack.config.dev.js
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.(css|less)$/,
use: ['style-loader', 'css-loader', 'less-loader'],
include: path.resolve('./src'),
},
{
test: /\.(png|jpg|jpeg)$/,
use: 'url-loader?limit=8192&name=images/[name].[hash].[ext]',
include: path.resolve('./src'),
},
]
}
...
};
limit:
表示超過多少就使用base64來代替怒炸,單位是byte
name:
可以設(shè)置圖片的路徑带饱,名稱和是否使用hash
babel,處理react語法和es新語法
babel是什么呢阅羹?纠炮?月趟?
這是官方解釋,意思是babel是一個javascript的編譯器恢口,可以讓你在現(xiàn)在用上下一代javascript孝宗。眾所周知,現(xiàn)在瀏覽器各自執(zhí)行的標(biāo)準(zhǔn)并不是很統(tǒng)一耕肩,版本不同因妇,支持的javascript的語法也不同,babel就是幫助我們把我們寫出來的新興javascript語法轉(zhuǎn)換成配置的瀏覽器版本可以識別的語法猿诸。具體的可以看Babel官網(wǎng)和Can i use官網(wǎng)
安裝babel和babel-loader
$ npm install babel-core babel-loader --save-dev
配置webpack.config.dev.js
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.(css|less)$/,
use: ['style-loader', 'css-loader', 'less-loader'],
include: path.resolve('./src'),
},
{
test: /\.(png|jpg|jpeg)$/,
use: 'url-loader?limit=8192&name=images/[name].[hash].[ext]',
include: path.resolve('./src'),
},
{
test: /\.(js|jsx)$/,
use: [
{
loader: 'babel-loader',
},
],
include: path.resolve('./src'),
},
]
}
...
};
如果這個時候你執(zhí)行一下npm run start
婚被,會發(fā)現(xiàn)報錯
提示我們?nèi)绻胋abel-loader@8的話,必須用babel的7版本以上梳虽,就是babel-core必須是7以上址芯,我們看一下我們的package.json
看問題就出在這里,所以我們需要重新安裝babel-loader窜觉,以搭配對應(yīng)的babel-core
$ npm install babel-loader@7
這樣我們就可以執(zhí)行npm run start
了
目前我還不知道babel的版本有什么區(qū)別谷炸,可以立個TODO,有空可以具體看一下babel的版本區(qū)別
現(xiàn)在我們還需要告訴babel我們用的是什么語法禀挫,在根目錄創(chuàng)建.babelrc
旬陡,其實我們把接下來的配置寫在webpack.config.dev.js里也是可以的
$ touch .babelrc
并且在.babelrc
中寫入
{
"presets": [
"es2015",
"react"
]
}
并且安裝對應(yīng)的處理插件
$ npm install babel-preset-es2015 babel-preset-react
使用HtmlWebpackPlugin插件
在我們之前打包后的目錄下只有一個js文件,而我們需要手動在./public/index.html
中引用才能起作用语婴,現(xiàn)在描孟,HtmlWebpackPlugin就是幫我們把打包后的js和html一起生成。這就是為什么稱./public/index.html
為模板的原因砰左。
安裝
$ npm install html-webpack-plugin
配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
filename: path.resolve('./dev', 'index.html'),
template: path.resolve('./public', 'index.html'),
})
]
};
現(xiàn)在執(zhí)行npm run start
以后匿醒,./dev
下面就會有一個js文件一個html文件,并且html里面已經(jīng)引用好了js
使用webpack-dev-server熱更新
現(xiàn)在有一種情況就是缠导,每次我們更改完文件廉羔,需要手動打包,然后手動刷新頁面酬核,就算我們用--watch
蜜另,還是會需要手動刷新頁面,才能看到我們更改后的樣子嫡意,現(xiàn)在有了webpack-dev-server举瑰,就省去了我們手動刷新頁面,并且是基于node在本地起一個服務(wù)以便于讓我們的代碼更真實的從服務(wù)器返回的場景蔬螟,而不是手動雙擊html文件了此迅。
安裝
$ npm install webpack-dev-server --save-dev
更改package.json中的start
命令
{
"scripts": {
"start": "webpack-dev-server --config webpack.config.dev.js"
}
}
更改webapck.config.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
devServer: {
"contentBase": './dev',
"compress": true,
},
};
contentBase:
表示server文件的根目錄
compress:
表示開啟gzip
webpack-dev-server默認(rèn)情況下會將output的內(nèi)容放在內(nèi)存中,是看不到物理的文件的,如果想看到文件耸序,需要下載另一個插件忍些。
這個時候如果你執(zhí)行了npm run start
,會看到如下畫
從圖上我們可以看到坎怪,webpack-dev-server幫我們在本地8080端口起了一個服務(wù)罢坝,并且直接訪問
./dev
目錄
模塊熱替換(Hot Module Replacement)
模塊熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允許在運行時更新各種模塊搅窿,webpack-dev-server雖然手動刷新頁面變成了自動刷新嘁酿,但是!男应!但是D炙尽!模塊熱替換可以把刷新都省了沐飘,頁面直接變游桩。
配置
更改webpack.config.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
...
devServer: {
contentBase: './dev',
compress: true,
hot: true,
},
plugins: [
new HtmlWebpackPlugin({
filename: path.resolve('./dev', 'index.html'),
template: path.resolve('./public', 'index.html'),
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
};
安裝react-hot-loader
$ npm install react-hot-loader
并在src目錄下新建Container.js
import React from 'react';
import { hot } from 'react-hot-loader';
import App from './App';
const Container = () => (
<App />
);
export default hot(module)(Container);
更改./src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Container from './Container';
ReactDOM.render(<Container />, document.getElementById('root'));
更改webpack.config.dev.js
{
"scripts": {
"start": "webpack --config webpack.config.dev.js"
}
}
執(zhí)行npm run start
,更改代碼保存耐朴,會發(fā)現(xiàn)頁面不會刷新借卧,但是內(nèi)容會改變,css自帶熱模塊替換隔箍,所以現(xiàn)在更改js和css谓娃,頁面都會自己的更替新的內(nèi)容
到這脚乡,用webpack構(gòu)建一個react開發(fā)環(huán)境已經(jīng)完成
啟用eslint
再說一下eslint蜒滩,沒有規(guī)矩,不成方圓奶稠,國有國法俯艰,家有家規(guī)。寫代碼自然也要遵守一定的規(guī)范锌订,當(dāng)然竹握,不遵守規(guī)范代碼也是可以跑通,但是在后期維護(hù)和易讀性上辆飘,肯定沒有按著一定規(guī)范寫出來的代碼好看啦辐。所以可以采用用eslint來進(jìn)行代碼規(guī)范檢查,并且選用airbnb這家公司的規(guī)范蜈项。
安裝
$ npm install -g eslint // 全局安裝eslint
$ eslint --init // 在項目跟目錄進(jìn)行eslint初始化芹关,并根據(jù)選擇,選擇airbnb規(guī)范
并且在自己的編輯器上配好eslint紧卒,該裝插件裝插件侥衬,該改設(shè)置改設(shè)置
結(jié)尾
在這我只是簡單的建了一個開發(fā)環(huán)境,生產(chǎn)環(huán)境有時間再出一個,對于各個loader還有很多的options可以設(shè)置轴总,webpack還有很多的插件都沒有涉及直颅,什么代碼分離,tree-shaking都沒有講到怀樟,大家可以自己查看webpack的相關(guān)文檔功偿,真的很有幫助。
加油往堡!