webpack 是一個現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(module bundler)饺汹。當(dāng) webpack 處理應(yīng)用程序時借尿,它會遞歸地構(gòu)建一個依賴關(guān)系圖(dependency graph),其中包含應(yīng)用程序需要的每個模塊鸯两,然后將所有這些模塊打包成一個或多個 bundle。
1.webpack 介紹
模塊化思想:
- 按照代碼的業(yè)務(wù)邏輯進(jìn)行劃分,分成一塊一塊沮峡,模塊復(fù)用化,提高效率亿柑。
- 項(xiàng)目按照不同類型的文件邢疙,分別進(jìn)行不同的管理
組件化思想:
組件化思想是對于不同的頁面,使用不同的組件望薄,從頁面的角度考慮疟游,是否有公共組件,實(shí)現(xiàn)組件復(fù)用痕支,組件化颁虐。(vue、react)
webpack可以看做是模塊打包機(jī):它做的事情是卧须,分析你的項(xiàng)目結(jié)構(gòu)另绩,找到JavaScript模塊以及其它的一些瀏覽器不能直接運(yùn)行的拓展語言(Scss儒陨,TypeScript等)、文件等笋籽,并將其轉(zhuǎn)換和打包為合適的格式供瀏覽器使用蹦漠。
2. webpack和Grunt和Gulp比較
Webpack和另外兩個并沒有太多的可比性,Gulp/Grunt是一種能夠優(yōu)化前端的開發(fā)流程的工具车海,而webpack是一種模塊化的解決方案笛园,不過Webpack的優(yōu)點(diǎn)使得Webpack在很多場景下可以替代Gulp/Grunt類的工具。
Grunt和Gulp的工作方式是:在一個配置文件中侍芝,指明對某些文件進(jìn)行類似編譯研铆,組合,壓縮等任務(wù)的具體步驟竭贩,工具之后可以自動替你完成這些任務(wù)蚜印。
Webpack的工作方式是:把你的項(xiàng)目當(dāng)做一個整體,通過一個給定的主文件(如:index.js)留量,Webpack將從這個文件開始找到你的項(xiàng)目的所有依賴文件窄赋,使用loaders處理它們,最后打包為一個(或多個)瀏覽器可識別的JavaScript文件楼熄。
3.webpack核心概念
3.1 入口(entry)
入口起點(diǎn)(entry point)指示 webpack 應(yīng)該使用哪個模塊忆绰,來作為構(gòu)建其內(nèi)部依賴圖的開始。進(jìn)入入口起點(diǎn)后可岂,webpack 會找出有哪些模塊和庫是入口起點(diǎn)(直接和間接)依賴的错敢。
entry: {[entryChunkName: string]: string|Array<string>}
// 在多頁應(yīng)用中,(譯注:每當(dāng)頁面跳轉(zhuǎn)時)服務(wù)器將為你獲取一個新的 HTML 文檔缕粹。頁面重新加載新文檔稚茅,并且資源被重新下載
// 使用 CommonsChunkPlugin 為每個頁面間的應(yīng)用程序共享代碼創(chuàng)建 bundle。由于入口起點(diǎn)增多平斩,多頁應(yīng)用能夠復(fù)用入口起點(diǎn)之間的大量代碼/模塊亚享,從而可以極大地從這些技術(shù)中受益
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
3.2 輸出(output)
配置 output 選項(xiàng)可以控制 webpack 如何向硬盤寫入編譯文件。注意绘面,即使可以存在多個入口起點(diǎn)欺税,但只指定一個輸出配置。
// 單個入口起點(diǎn)
const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
// 多個入口起點(diǎn)
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
3.3 loader
Loaders是webpack提供的最激動人心的功能之一了揭璃。通過使用不同的loader晚凿,webpack有能力調(diào)用外部的腳本或工具,實(shí)現(xiàn)對不同格式的文件的處理瘦馍,比如說分析轉(zhuǎn)換scss為css歼秽,或者把下一代的JS文件(ES6,ES7)轉(zhuǎn)換為現(xiàn)代瀏覽器兼容的JS文件情组,對React的開發(fā)而言哲银,合適的Loaders可以把React的中用到的JSX文件轉(zhuǎn)換為JS文件扛吞。
module.rules
允許你在 webpack 配置中指定多個 loader。 這是展示 loader 的一種簡明方式荆责,并且有助于使代碼變得簡潔。同時讓你對各個 loader 有個全局概覽亚脆,Loaders的配置包括以下幾方面:
- test:一個用以匹配loaders所處理文件的拓展名的正則表達(dá)式(必須)
- loader:loader的名稱(必須)
- include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不需要處理的文件(文件夾)(可選)做院;
- query:為loaders提供額外的設(shè)置選項(xiàng)(可選)
load的特性
- loader 支持鏈?zhǔn)絺鬟f。能夠?qū)Y源使用流水線(pipeline)濒持。一組鏈?zhǔn)降?loader 將按照相反的順序執(zhí)行键耕。loader 鏈中的第一個 loader 返回值給下一個 loader。在最后一個 loader柑营,返回 webpack 所預(yù)期的 JavaScript屈雄。
- loader 可以是同步的,也可以是異步的官套。
- loader 運(yùn)行在 Node.js 中酒奶,并且能夠執(zhí)行任何可能的操作。
- loader 接收查詢參數(shù)奶赔。用于對 loader 傳遞配置惋嚎。
- loader 也能夠使用 options 對象進(jìn)行配置。
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
- 除了使用 package.json 常見的 main 屬性站刑,還可以將普通的 npm 模塊導(dǎo)出為 loader另伍,做法是在 package.json 里定義一個 loader 字段。
- 插件(plugin)可以為 loader 帶來更多特性绞旅。
- loader 能夠產(chǎn)生額外的任意文件摆尝。
loader列表
3.4 插件(plugins)
插件(Plugins)是用來拓展Webpack功能的,它們會在整個構(gòu)建過程中生效因悲,執(zhí)行相關(guān)的任務(wù)堕汞。
- 插件的使用
要使用某個插件,我們需要通過npm安裝它囤捻,然后要做的就是在webpack配置中的plugins關(guān)鍵字部分添加該插件的一個實(shí)例(plugins是一個數(shù)組)臼朗。
const webpack = require('webpack');
module.exports = {
...
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true
}
}, {
loader: "postcss-loader"
}
]
}
]
},
plugins: [
new webpack.BannerPlugin('版權(quán)所有,翻版必究')
],
};
**1. HtmlWebpackPlugin插件**
這個插件的作用是依據(jù)一個簡單的index.html模板蝎土,生成一個自動引用你打包后的JS文件的新index.html视哑。
npm install --save-dev html-webpack-plugin
plugins: [
new HtmlWebpackPlugin({
template: __dirname + "/app/index.html"http://new 一個這個插件的實(shí)例,并傳入相關(guān)的參數(shù)
})
],
**2. Hot Module Replacement (HMR)熱加載**
它允許你在修改組件代碼后誊涯,自動刷新實(shí)時預(yù)覽修改后的效果挡毅。
3. 其他插件
- OccurenceOrderPlugin :為組件分配ID,通過這個插件webpack可以分析和優(yōu)先考慮使用最多的模塊暴构,并為它們分配最小的ID
- UglifyJsPlugin:壓縮JS代碼跪呈;
- ExtractTextPlugin:分離CSS和JS文件
4. webpack打包速度優(yōu)化
// 1.HotModuleReplacementPlugin 熱加載模塊使用
// 2.選擇一個合適的devtool屬性值 推薦:cheap-module-eval-source-map
// 3. 代碼壓縮用ParallelUglifyPlugin代替自帶的 UglifyJsPlugin插件段磨。
// 自帶的JS壓縮插件是單線程執(zhí)行的,而[webpack-parallel-uglify-plugin](https://github.com/gdborton/webpack-parallel-uglify-plugin)可以并行的執(zhí)行
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
comments: false
},
compress: {
warnings: false
}
}
})
// 4.CommonsChunkPlugin插件提取公共模塊
// 提取公共模塊文件
new webpack.optimize.CommonsChunkPlugin({
chunks: ['home', 'detail'],
// 開發(fā)環(huán)境下需要使用熱更新替換耗绿,而此時common用chunkhash會出錯苹支,可以直接不用hash
filename: '[name].js' + (isProduction ? '?[chunkhash:8]' : ''),
name: 'common'
}),
// 切合公共模塊的提取規(guī)則,有時后你需要明確指定默認(rèn)放到公共文件的模塊
// 文件入口配置
entry: {
home: './src/js/home',
detail: './src/js/detail',
// 提取jquery入公共文件
common: ['jquery', 'react', 'react-dom']
},
4. webpack使用
4.1 非配置文件命令行命令執(zhí)行
# webpack非全局安裝的情況
node_modules/.bin/webpack 入口文件 出口文件
#webpack 全局安裝情況
webpack 入口文件 出口文件
webpack 的全局安裝误阻。
# 全局安裝webpack
npm install webpack -g
# 將webpack安裝到項(xiàng)目中
npm install webpack --save-dev
4.2 webpack配置文件使用
webpack的配置文件债蜜,使用vue-cli生成的
// webpack.config.js
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
chunkFilename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
}
}
打包命令,可以使用npm相關(guān)配置究反,完成打包寻定,再項(xiàng)目的pakage.json文件中,對scripts對象進(jìn)行相關(guān)設(shè)置即可精耐。
{
"name": "tapp",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "scott",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js" // 修改的是這里狼速,JSON文件不支持注釋,引用時請清除
},
"dependencies": {
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",
"echarts": "^4.1.0",
}
}
4.3 使用webpack構(gòu)建本地服務(wù)器(devServer)
如何讓你的瀏覽器監(jiān)聽你的代碼的修改卦停,并自動刷新顯示修改后的結(jié)果------熱加載
其實(shí)Webpack提供一個可選的本地開發(fā)服務(wù)器向胡,這個本地服務(wù)器基于node.js(vue-cli使用的是express)構(gòu)建,可以實(shí)現(xiàn)你想要的這些功能沫浆,不過它是一個單獨(dú)的組件捷枯,在webpack中進(jìn)行配置之前需要單獨(dú)安裝它作為項(xiàng)目依賴。(vue-cli默認(rèn)安裝了依賴)
npm install --save-dev webpack-dev-server
webpack-dev-server的配置文件
// devServer服務(wù)器
devServer: {
clientLogLevel: 'warning', // LogLevel Possible values are none, error, warning or info (default). 日志級別
// When using the HTML5 History API, the `index.html` page will likely have to be served in place of any `404` responses专执。替換404請求的頁面
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true, // Enable webpack's Hot Module Replacement feature 熱加載
contentBase: false, // since we use CopyWebpackPlugin.
compress: true, // Enable gzip compression for everything served 是否啟用壓縮
host: HOST || config.dev.host, // url
port: PORT || config.dev.port, // 端口
open: config.dev.autoOpenBrowser, // 是否自動打開瀏覽器
openPage: config.dev.openPage, // 打開瀏覽器的地址
// 當(dāng)存在編譯器錯誤或警告時淮捆,在瀏覽器中顯示全屏覆蓋。默認(rèn)情況下禁用
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
// 根路徑
publicPath: config.dev.assetsPublicPath,
// 啟用代URL
proxy: {
'/IntelligentWaterAffairs': {
target: 'http://39.104.178.72:8080/', // 接口域名 //server
changeOrigin: true, //是否跨域
}
},
quiet: true, // necessary for FriendlyErrorsPlugin
// 啟用輪詢
watchOptions: {
poll: config.dev.poll,
}
}
config/index.js 啟用devtool
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
5. Babel
- Babel是什么本股?
Babel其實(shí)是一個編譯JavaScript語言的平臺攀痊。 - Babel的目的是要達(dá)到那種效果?
- 讓你能使用最新的JavaScript代碼(ES6拄显,ES7...)苟径,而不用管新標(biāo)準(zhǔn)是否被當(dāng)前使用的瀏覽器完全支持;
- 讓你能使用基于JavaScript進(jìn)行了拓展的語言躬审,比如Vue的JSX棘街;
- Babel是怎樣配置的?
babel的配置選項(xiàng)放在一個單獨(dú)的名為 ".babelrc" 的配置文件中承边。
- 安裝babel
npm install --save-dev babel-loader babel-core babel-preset-env babel-plugin-transform-runtime babel-plugin-istanbul babel-polyfill babel-preset-stage-2 babel-register
- babelrc文件配置
{
"presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"],
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
3.webpack.config.js 配置
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
參考資料: 部分內(nèi)容來源于參考資料遭殉。
https://www.webpackjs.com/concepts/
https://segmentfault.com/a/1190000006178770#articleHeader5