webpack其實是一個靜態模塊打包工具css
webpack 處理項目時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。html
npm run dev
npm run build
複製代碼
...
"scripts": {
"dev_def": "webpack-dev-server --inline --public --config build/dev.js",
"dev": "nodemon --watch config/index.js --exec \"webpack-dev-server --inline --public --config build/dev.js\"",
"start": "npm run dev",
"build": "cross-env NODE_ENV=production node build/build.js"
}
...
複製代碼
是一個輕量級的服務器,修改文件源碼後,自動刷新頁面將修改同步到頁面上vue
webpack-dev-server --inline --public --config build/dev.js
複製代碼
module.exports = {
//...
devServer: {
inline: true
}
};
複製代碼
會監測項目中的文件,一旦發現文件有改動,Nodemon 會自動重啓應用node
nodemon --watch config/index.js --exec \"webpack-dev-server --inline --public --config build/dev.js\" 複製代碼
這句話的意思就是: 用nodemon監控config/index.js文件,若是有變化,則從新執行【webpack-dev-server --inline --public --config build/dev.js】的命令linux
而【webpack-dev-server --inline --public --config build/dev.js】命令對項目自己具備熱更新功能,但webpack配置文件修改時,dev-sever自己不會生效。而用nodemon就是在webpack配置文件修改時也重啓服務,算是一個自動補充webpack
解決跨平臺設置和使用環境變量的腳本,如變量名稱、路徑方面的抹平es6
module.exports = {
// 入口文件
entry: {
app: './src/js/index.js'
},
// 在哪裏輸出它所建立的 bundles
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/' //確保文件資源可以在 http://localhost:3000 下正確訪問
},
// 開發者工具 source-map
devtool: 'inline-source-map',
// 建立開發者服務器
devServer: {
contentBase: './dist',
hot: true // 熱更新
},
plugins: [
// 刪除dist目錄
new CleanWebpackPlugin(['dist']),
// 從新穿件html文件
new HtmlWebpackPlugin({
title: 'Output Management'
}),
// 以便更容易查看要修補(patch)的依賴
new webpack.NamedModulesPlugin(),
// 熱更新模塊
new webpack.HotModuleReplacementPlugin()
],
// 環境
mode: "development",
// loader配置
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
}
複製代碼
__dirname: 當前文件所在文件夾的絕對路徑web
entry: './path/to/my/entry/file.js'
// 或者(對象寫法)
entry: {
main: './path/to/my/entry/file.js'
}
複製代碼
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
複製代碼
entry:{
vendor:[resolve('src/lib/polyfill.js'), 'vue', 'vue-router'], // 不推薦
app: resolve('src/main.ts')
}
複製代碼
在webpack4以前的版本中,一般將供應商添加爲單獨的入口點,以將其編譯爲單獨的文件vendor(與之結合使用CommonsChunkPlugin)vue-router
在webpack 4中不鼓勵這樣作。相反,該optimization.splitChunks選項負責分離供應商和應用程序模塊並建立單獨的文件。不要爲供應商或其餘不是執行起點的東西建立條目。npm
output: {
filename: '[name].bundle.js',
chunkFilename: [name].min.js,
path: path.resolve(__dirname, 'dist'),
publicPath: '/' //確保文件資源可以在 http://localhost:3000 下正確訪問
}
複製代碼
// dev
devtool: 'eval-source-map'
// prod
devtool: 'source-map'
複製代碼
關鍵字揭祕:
關鍵字 | 含義 |
---|---|
eval | 在打包的時候,生成的bundle.js文件,模塊都被eval包裹,而且後面跟着sourceUrl,指向的是原文件 |
source-map | 這種配置會生成一個帶有.map文件,這個map文件會和原始文件作一個映射,調試的時候,就是經過這個.map文件去定位原來的代碼位置的 |
cheap | 低消耗打包,就是打包的時候map文件,不會保存原始代碼的列位置信息,只包含行位置信息,因此這就解釋官網圖後面的說明(僅限行) |
... | ... |
devServer: {
compress: true,
port: 9000,
hot: true,
https: true,
overlay: {
warnings: false,
errors: true
},
publicPath: '/platform/redapply/'
}
複製代碼
// dev
mode: 'development'
// build
mode: 'production'
複製代碼
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
]
複製代碼
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
複製代碼
對於loader的執行順序,是從後往前的
resolve: {
extensions: ['.js','.ts', '.vue', '.json'],
alias: {
'@lib': resolve('src/lib'),
'@models': resolve('build/models'),
'@components': resolve('src/components'),
'@data': resolve('src/data'),
'@': resolve('src')
}
}
複製代碼
好比定義一些公共的scss文件。爲了避免再每一個頁面都引入該文件。咱們能夠設置文件預加載
module: {
rules: [
...
{
test: /\.sass|scss|css$/,
use: [
...
{
loader: 'sass-resources-loader',
options: {
resources: [
path.resolve(__dirname, '../src/assets/css/vars.scss'),
path.resolve(__dirname, '../src/assets/css/common.scss')
]
}
}
]
}
]
}
複製代碼
optimization: {
minimize: true, // 默認爲true,效果就是壓縮js代碼。
minimizer: [ // 壓縮時調用的插件
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({})
],
runtimeChunk: { // 默認爲false,抽離出運行時公共代碼塊。
name: 'manifest'
},
splitChunks:{
chunks: 'all', // 必須三選一: "initial" | "all"(推薦) | "async" (默認就是async)
minSize: 30000, // 生成塊的最小字節數,30000
minChunks: 1, // 最少被引用的次數
maxAsyncRequests: 3, // 按需加載時候最大的並行請求數
maxInitialRequests: 3, // 一個入口最大的並行請求數
name: true, // 打包的chunks的名字
cacheGroups: { // 緩存配置
common: {
name: 'common', // 要緩存的 分隔出來的 chunk 名稱
chunks: 'initial', // 必須三選一: "initial" | "all" | "async"(默認就是async)
priority: 11,
enforce: true,
reuseExistingChunk: true, // 可設置是否重用該chunk
test: /[\/]node_modules[\/](vue|babel\-polyfill|mint\-ui)/
},
vendor: { // key 爲entry中定義的 入口名稱
name: 'vendor', // 要緩存的 分隔出來的 chunk 名稱
chunks: 'initial', // 必須三選一: "initial" | "all" | "async"(默認就是async)
priority: 10,
enforce: true,
reuseExistingChunk: true, // 可設置是否重用該chunk
test: /node_modules\/(.*)\.js/
},
styles: {
name: 'styles',
test: /\.(scss|css)$/,
chunks: 'all',
minChunks: 1,
reuseExistingChunk: true,
enforce: true
}
}
}
}
複製代碼
默認爲false, 抽離出運行時公共代碼塊
什麼是運行時(runtime)?
JS在瀏覽器中能夠調用瀏覽器提供的API,如window對象,DOM相關API等。這些接口並非由V8引擎提供的,是存在與瀏覽器當中的。所以簡單來講,對於這些相關的外部接口,能夠在運行時供JS調用,以及JS的事件循環(Event Loop)和事件隊列(Callback Queue),把這些稱爲RunTime。有些地方也把JS所用到的core lib核心庫也看做RunTime的一部分。
chunk運行時
在chunk執行的時候所依賴的環境(方法)
function (chunk) | string
這表示將選擇哪些塊進行優化
string:
function:
splitChunks: {
chunks (chunk) {
// exclude `my-excluded-chunk`
return chunk.name !== 'my-excluded-chunk';
}
}
複製代碼
緩存組能夠繼承和/或覆蓋任何選項splitChunks.*;要禁用任何默認緩存組,請將其設置爲false。
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 3,
maxInitialRequests: 3,
name: true,
cacheGroups: {
common: {
name: 'common',
chunks: 'initial',
priority: 11,
enforce: true,
reuseExistingChunk: true, // 可設置是否重用該chunk
test: /[\/|\\]node_modules[\/|\\](vue|babel\-polyfill|mint\-ui)/
},
vendor: {
name: "vendor",
chunks: "initial",
priority: 10,
test: /[\/|\\]node_modules[\/|\\](.*)\.js/
},
styles: {
name: 'styles',
test: /\.(scss|css|less)$/,
chunks: 'initial',
minChunks: 1,
reuseExistingChunk: true,
enforce: true
}
}
}
}
複製代碼
注意:
這裏有個坑,就是關於test匹配路徑的問題 通常網上看到的如:
...
common: {
name: 'common',
chunks: 'initial',
priority: 11,
enforce: true,
reuseExistingChunk: true,
test: /[\/]node_modules[\/](vue|babel\-polyfill|mint\-ui)/
}
...
複製代碼
這裏面test匹配正則是根據linux環境路徑匹配的。(如:node_modules/vue)
但window路徑和linux路徑不同,它是反斜槓。(如:node_modules\vue)
這樣咱們要把正則改爲
/[\/|\\]node_modules[\/|\\](vue|babel\-polyfill|mint\-ui)/
複製代碼
這樣就能夠兼容兩種環境了
一般來說webpack就須要3個配置文件
但在咱們的項目裏你們看到的配置和上面介紹的並不徹底相同。
是由於:咱們在腳手架生成項目的時候,已經集成了webpack的基本配置。
它們都在@zz/webpack-vue下
而咱們項目中僅暴露了一些配置對象入口。
暴露出來的配置項結構和webpack自己的略有區別。
開發人員能夠經過自定義這些對象,而後程序會和默認的配置進行合併,造成最終的配置參數。
(本文爲內部專題學習webpack的一次分享,內容比較基礎)