最近學習了一波webpack打包部署,作為一名前端授艰,不會一個打包的工具可真的是丟人啊辨嗽。不過,用webpack又要接觸到了配置文件淮腾,這個當初當我放棄寫后端的東西糟需,不過以后還是要全面發(fā)展的。好了谷朝,話不多說洲押,這篇文章用的是webpack4.x版本的,下面將細數(shù)當初才過的坑圆凰。
1.基礎準備
創(chuàng)建一個文件夾webpackDemo杈帐,我們使用命令行進入這個文件夾,運行 npm init
命令专钉,初始化這個文件夾挑童,初始化過程中出現(xiàn)的詢問的一些配置,一路回車就好了跃须。初始化好了之后站叼,我們會發(fā)現(xiàn)文件夾里面已經(jīng)多了package.json文件。
npm install webpack --save-dev webpack-cli --save-dev
安裝必要的 webpack 和 webpack-cli菇民,安裝成功之后的package.json文件如下
在根目錄下創(chuàng)建如下的目錄結構
在test.js
文件里面編寫如下代碼尽楔,一萬年經(jīng)典的Hello World
document.write("Hello World");
在index.html
里面編寫代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Webpack初探</title>
</head>
<body>
<script src="./dist/js/bundle.js"></script>
</body>
</html>
這邊引用一個bundle.js
文件,bundle.js
文件使我們打包之后生成的文件第练,接下來使用webpack的打包命令進行打包
webpack src/apps/test.js -o dist/js/bundle.js
wepack的基礎打包命令 webpack {entryFile} -o {aimFile}
執(zhí)行完之后會發(fā)現(xiàn)我們的目錄里已經(jīng)生成了 bundle.js
文件阔馋,我們運行 index.html
文件,可以看到親切的Hello World了娇掏。
打包過程中垦缅,出現(xiàn)的輸出如下
這邊會顯示webpack打包一共花了501ms,打包后的 bundle.js
體積是957bytes驹碍,因為我們的代碼比較簡單壁涎,所以打包生成的文件還是很小的。
2.webpack.config.js配置文件
在根目錄下創(chuàng)建文件 webpack.config.js
這是weback運行所要依據(jù)的配置志秃。大致分為入口配置怔球,出口配置,loader配置浮还,plugins配置
2.1 entry和output###
entry配置的是入口文件竟坛,告訴webpack從哪個文件開始解析,分為單入口和多入口钧舌。有了入口担汤,就要配置出口,配置打包生成的文件位置和文件名稱洼冻。在webpack.config.js
里面編寫如下代碼
const path = require('path');
module.exports = {
entry: path.resolve(__dirname, 'src/apps/test.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: "js/bundle.js",
}
}
首先這邊引用的path
是node.js
的一個模塊崭歧,是用來解析路徑用的,path.resolve
指的是當前文件的所在路徑撞牢,那么這邊我們entry
配置的就是/src/apps/test.js
率碾,這是單入口的配置形式。
下面對出口進行配置屋彪,output是一個對象所宰,基礎的兩個屬性,一個是輸出文件的路徑畜挥,另一個是輸出文件的名稱仔粥。
在package.json
里面編寫如下代碼:
這邊配置一下webpack的打包命令,之后通過npm run start
進行打包蟹但,就不需要輸一大串的命令了躯泰。打包一下我們可以看一下控制臺的輸出
發(fā)現(xiàn)有一個warning,這是因為我們還沒有配置我們的mode矮湘,我們修改webpack.config.js
文件
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: path.resolve(__dirname, 'src/apps/test.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: "js/bundle.js",
}
}
在打包一下會發(fā)現(xiàn)這邊的warning已經(jīng)沒有了斟冕。
2.2 devtool配置
上面的配置文件我們是加了一個devtool
的配置,這是因為webpack打包后的這個文件缅阳,我們可以看一下磕蛇,已經(jīng)不是我們所熟知的代碼了,這樣不方便于我們的調試十办,所以webpack為了解決這個問題秀撇,有一個devtool
的配置。這邊給一個別人博客的傳送門webpack之devtool詳解向族,webpack官方解釋
2.3 loader配置
loader配置是webpack中的重點呵燕,因為webpack默認是只能處理html文件,如果要處理比如react應用中的jsx文件那么就需要配置一下loader件相,或者js再扭、css等文件氧苍,都需要配置一下loader。這邊已react應用為例泛范。由于目前瀏覽器的兼容性問題让虐,所以我們需要大量的插件和loader來轉換我們寫的高級js語法,就有了各種es6轉es5罢荡,es7啥的赡突。具體的還得好好研究。首先安裝react相關的插件
npm install react --save react-dom --save
安裝解析react的相關插件和解析es6語法的相關插件区赵。
npm install babel-loader -save-dev babel-core --save-dev babel-preset-env --save-dev babel-preset-react --save-dev
babel-core
把 js 代碼分析成 ast (抽象語法樹, 是源代碼的抽象語法結構的樹狀表現(xiàn)形式)惭缰,方便各個插件分析語法進行相應的處理。有些新語法在低版本 js 中是不存在的笼才,如箭頭函數(shù)漱受,rest 參數(shù),函數(shù)默認值等患整,這種語言層面的不兼容只能通過將代碼轉為 ast拜效,再通過語法轉換器分析其語法后轉為低版本 js。
babel-preset-*
babel-preset-* 代表了一系列的轉碼插件
有了 babel-plugin 系列各谚,可以按需配置自己想要的特性紧憾,若是想搭個 es6 環(huán)境,一個個地配置各個插件昌渤,我猜你會瘋掉赴穗。babel-preset 系列就可以滿足我們的需求,babel-preset 系列打包了一組插件膀息,類似于餐廳的套餐般眉。如 babel-preset-es2015 打包了 es6 的特性,babel-preset-stage-0 打包處于 strawman 階段的語法
下面看具體的配置潜支,配置文件如下甸赃,這邊首先我們要將package.json文件里面的babel-loader的版本更換成7.1.5然后重新安裝一下模塊,不然下面會因為babel-loader的版本問題出現(xiàn)打包失敗的問題冗酿。
// webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: path.resolve(__dirname, 'src/apps/console.jsx'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: "js/bundle.js",
},
module: {
rules: [{
test: /(\.js)|(\.jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
}]
}
}
test 指明要對哪一種后綴的文件進行解析埠对,使用正則進行驗證
exclude 規(guī)定一些文件夾或文件不參與解析
use.loader 配置使用的loader名稱
use.option 配置loader的其他選項,這邊的presets是告訴webpack解析react語法和es6語法裁替。
// console.jsx
import React from 'react';
import ReactDOM from 'react-dom';
const mountNode = document.getElementById("root");
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
Hello China!
</div>
);
}
}
ReactDOM.render(<App />, mountNode);
執(zhí)行npm run start
项玛,然后運行我們的index.html文件可以看到Hello China!弱判。
2.4 plugin配置
插件賦予了webpack更多的功能襟沮,比如說 js和css分離打包。比如說happyPack的多線程打包,比如說每次打包前自動清空dist目錄开伏。
以js膀跌、css分離打包為例,這是使用的extract-text-webpack-plugin
插件硅则,
首先安裝一下淹父,注意這邊安裝的是extract-text-webpack-plugin@next
而不是extract-text-webpack-plugin
npm install --save-dev extract-text-webpack-plugin@next
npm install style-loader --save-dev css-loader --save-dev
// webpack.config.js
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: path.resolve(__dirname, 'src/apps/console.jsx'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: "js/bundle.js",
},
module: {
rules: [{
test: /(\.js)|(\.jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
}, {
test: /\.css$/i,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader']
})
}]
},
plugins: [
new ExtractTextPlugin({
filename: 'style/css/[name].css',
allChunks: true
})
]
}
2.5 其他配置###
stats配置
在進行webpack打包的時候會出現(xiàn)很多的輸出,但是有的輸出是我們不需要看見的輸出怎虫,這就可以采用stats進行配置
// 對webpack輸出信息的配置,可以減少一些不必要的輸出
stats: {
children: false
}
resolve.extensions 解決引入模塊不需要加后綴
// extensions 自動解決擴展困介,配置這個在引用模塊時不用加后綴
// modules 配置解析模塊的搜索目錄
// path.resolve 返回參數(shù)的絕對路徑 path.join 拼接路徑 然后返回絕對路徑
resolve: {
modules: [path.resolve(__dirname, 'node_modules'), path.join(__dirname, 'src')],
extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx']
},
optimization配置 抽離公共模塊
optimization: {
minimize: false,
splitChunks: {
chunks: 'all',
name: 'common'
}
},
last.一些解釋及踩過的那些坑
last.1 npm install 的時候 --save-dev 和--save的區(qū)別
首先這邊的 --save
是將我們install的包寫進package.json文件里面大审,后面的-dev才是要描述的重點,-dev
是寫進我們的devDependencies
里面座哩,如果不加這個那么是寫進dependencies
里面的徒扶,在生產(chǎn)環(huán)境下,是不會安裝devDependencies
里面的包的根穷。這邊找了一個別人的博客姜骡,寫的比我這個更全面一點。對--save-dev和--save的區(qū)別詳解
last.2 webpack基礎命令打包的時候報ERROR in multi ./src/apps/test.js dist/js/bundle.js
Module not found: Error: Can't resolve 'dist/js/bundle.js' in 'F:\WebDemo\webpackDemo'
這是因為webpack的版本問題屿良,在webpack4.x版本之前的打包命令是
webpack {entryFile} {aimFile}
但是在webpack4.x開始基礎打包命令就變成了
webpack {entryFile} -o {aimFile}
last.3出現(xiàn)Error: Cannot find module '@babel/core'###
這是因為babel-loader
版本的問題圈澈,如果之前我們安裝babel-loader
的時候是采用npm install babel-loader
這樣寫的話是默認安裝最新版本的babel-loader
最新的是8.x的,我們回退到7.1.5版本就可以避免這個報錯了尘惧。
last.4 webpack-dev-server問題
1.webpack-dev-server 不會讀取webpack.config.js配置的output也不會將生產(chǎn)的文件添加進項目目錄里
2.webpack-dev-server 生成的文件和你dist里面的文件不是同一個文件康栈。dist里面的是output里面決定
的webpack-dev-server打包生成的文件位置取決于contentBase配置
last.5 的 package.json里面的打包命令###
--colors 輸出結果帶有顏色
--profile 輸出性能數(shù)據(jù)看見每一步的耗時
--proress 輸出當前的編譯進度
--display-error-details 輸出詳細的錯誤信息
lats.6 使用extractTextPlugin時報 Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead###
這是因為安裝extract-text-webpack-plugin
的時候安裝命令問題,實際上我們需要安裝的是
"extract-text-webpack-plugin": "^4.0.0-beta.0",
解決辦法喷橙,刪除之前安裝的extract插件啥么,更換安裝命令為
npm install --save-dev extract-text-webpack-plugin@next
last.7 入口文件配置[name].js 但是打包出來的文件總是main.js并不會根據(jù)入口名稱決定出口名稱###
這邊的main.js main是取決你的主入口的,就是在執(zhí)行npm init的時候那一堆默認的主入口贰逾。之所以沒有按照入口文件來改變出口文件的名稱悬荣,是因為入口文件采用的單入口的形式,也就是如下寫法
entry: path.resolve(__dirname, 'src/apps/console.jsx')
使用單入口的形式疙剑,那么
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].js'
},
打包生成的文件只會有一個main.js 并不會生成console.js
解決辦法是將單入口的寫法換成多入口的形式氯迂,也就是下面這種寫法
entry: {
console: path.resolve(__dirname, 'src/apps/console')
},
這樣打包出來的文件就是console.js
last.7 bundle.js和vendor.js的引入順序問題###
vendor.js一定是最先引用的,因為bundle.js要依賴于vendor.js生存核芽。
last.8 名詞解釋
webpack.config.dev.js 開發(fā)環(huán)境下的webpack配置文件
webpack.config.prod.js 生產(chǎn)環(huán)境下的配置文件
vendor.js 這是打包我們引入的第三方包的囚戚。