原文鏈接:banggan.github.io/2019/05/09/…
Webpack核心概念解析
終于忙完了論文,可以愉快的開始學習了,重拾起重學前端、webpack以及Vue的源碼解讀作為入職前的復習吧。整個webpack系列將分成五個大的部分進行,以webpack4.0為文檔進行解讀,從簡單的概念解讀到最后的實現。 整個知識點涉及范圍:
loader
使用loader來預處理文件,把不同的靜態資源(模塊的結尾不是js的模塊)打包成js文件
loader打包靜態資源
打包圖片
- 安裝使用file-loader實現:npm install file-loader -D
- 在webpack.config.js中添加loader的配置
module.exports = {//打包項目的入口文件entry:
'./src/index.js',module:{rules:[{
test:/\.(jpg|png|gif)$/,//打包以jpg、png、gif結尾的所有圖片文件use:{loader:
'file-loader',options:{//placeholder 占位符 name:
'[name]_[hash].[ext]',//保持原圖片的名字+
hash值和后綴,主要單引號outputPath:
'image/'//打包圖片的位置}}}]}
}
復制代碼打包圖片成base64格式
url-loader基本能實現file-loader的打包功能,適用于小圖片的打包
- 好處:圖片打包成js文件,不用加載圖片的地址,頁面快速顯示
- 壞處:圖片過大導致js文件過大
所以,當圖片的大小小于limit值時會把圖片打包成base64格式,大于limit值則按照file-loader打包成圖片文件
- 安裝使用url-loader實現:npm install url-loader -D
- 在webpack.config.js中添加loader的配置
module.exports = {module:{rules:[{//打包以jpg、png、gif結尾的所有圖片文件
test:/\.(jpg|png|gif)$/,use:{loader:
'url-loader',options:{//placeholder 占位符 name:
'[name]_[hash].[ext]',//保持原圖片的名字+
hash值和后綴,主要單引號outputPath:
'image/',//打包圖片的位置
limit:2048}}]}
}
復制代碼打包樣式css文件
需要使用css-loader、style-loader
- css-loader:分析幾個css文件的關系,合并css文件
- style-loader:將css-loader合并的css內容掛載在頁面的head部分
實現方式:
- 安裝loader實現:npm install css-loader style-loader -D
- 在webpack.config.js中添加loader的配置
module.exports = {module: {rules: [{//打包css文件
test:/\.css$/,use:[
'style-loader',
'css-loader']}]}
}
復制代碼打包樣式scss文件
需要使用sass-loader、node-sass
- 安裝loader實現:npm install sass-loader node-sass -D
- 在webpack.config.js中添加loader的配置
module.exports = {module: {rules: [{
test: /\.scss$/,use:[
'style-loader',
'css-loader',
'sass-loader'] }]}
};
復制代碼在配置中,有三個loader,執行順序是從下到上,從右到左。在打包scss文件時,首先執行sass-loader:對sass翻譯成css文件,在掛載到css-loader,最后style-loader.
為樣式添加不同瀏覽器的前綴
為了兼容不同的瀏覽器,在寫樣式的時候需要加上適用不同瀏覽器的前綴,如-o、-webkit、-moz等
-安裝loader實現:npm install postcss-loader autoprefixer -D -在根目錄創建postcss.config.js
moudle.exports ={plugins:[require(
'autoprefixer')]
}
復制代碼- 在webpack.config.js中添加loader的配置
module.exports = {module: {rules: [{
test:/\.scss$/,use:[
'style-loader',
'css-loader',
'sass-loader',
'postcss-loader']}]}
}
復制代碼- 更多的有關于postcss-loader的配置見文檔
css-loader添加不同的配置
css模塊化打包
- 場景:在文件引入的scss不僅影響當前的文件,還影響當前文件引入的其他js文件,造成樣式沖突
- 實現:css只在當前模塊類有效,在配置中添加modules:true開啟css的模塊化打包,在引入的時候注意區分
scss文件的嵌套引用
module:{rules:[{//打包scss文件
test:/\.scss$/,use:[
'style-loader',{loader:
'css-loader',options:{importLoaders:2,//index.scss中通過import引入其他的scss文件,引入的scss文件在打包的時候也將依次經過所有的loadermodules:
true }},
'sass-loader',
'postcss-loader']}]}
復制代碼打包字體圖標文件
在阿里巴巴矢量圖標庫中,把需要的字體圖標下載到本地,解壓。將iconfont.eot iconfont.svg iconfont.ttf iconfont.woff 四種圖片文件放入到項目中,在src中新建一個放字體圖標的文件夾font。將iconfont.css文件拷貝到項目中,修改對應字體的引用路徑。
- 需要安裝 file-loader:npm i file-loader -D
- 在webpack.config.js中添加loader的配置
module.exports = {...module: {rules: [{
test: /\.(eot|ttf|svg|woff)$/,use:{loader:
'file-loader'}},]}]}
}
復制代碼打包數據文件
如遇到json、scv、xml文件需要打包時,使用csv-loader 和 xml-loader實現。
- 安裝:npm install csv-loader xml-loader -D
- 在webpack.config.js中添加loader的配置
module.exports = {module: {rules: [{
test: /\.(csv|tsv)$/,use: [
'csv-loader']},{
test: /\.xml$/,use: [
'xml-loader']}]}}
復制代碼plugins
loaders可以將各個類型的靜態資源打包成webpack能處理的模塊,而plugins有更強大的功能。它可以從打包優化和壓縮,一直到重新定義環境中的變量。
plugin可以在webpack運行到某一個時刻,自動完成一些事情。
自動生成html文件,并引入打包生成的js文件到生成的html文件中
- 安裝使用HtmlWebpackPlugin實現:npm install html-webpack-plugin -D
- 在webpack.config.js中添加loader的配置
在src中創建一個html的模板,在HtmlWebpackPlugin的配置中引入該模板,打包后生成和模板類似的html文件并引入打包的js文件。
const HtmlWebpackPlugin = require(
'html-webpack-plugin');
const path = require(
'path');module.exports = {entry:
'index.js',output: {path: path.resolve(__dirname,
'./dist'),filename:
'index_bundle.js'},plugins: [new HtmlWebpackPlugin({template:
'src/index.html' })]
}
復制代碼- 更多的有關于HtmlWebpackPlugin的配置見文檔
自動清除上一次打包的dist文件
先刪除上一次打包的dist文件,再執行打包
- 安裝使用CleanWebpackPlugin 實現:npm install clean-webpack-plugin -D
- 在webpack.config.js中添加loader的配置
const HtmlWebpackPlugin = require(
'html-webpack-plugin');
const CleanWebpackPlugin = require(
'clean-webpack-plugin');
const path = require(
'path');module.exports = {entry:
'index.js',output: {path: path.resolve(__dirname,
'./dist'),filename:
'index_bundle.js'},plugins: [new HtmlWebpackPlugin({template:
'src/index.html' }),new CleanWebpackPlugin([
'dist']), // 在打包之前,可以刪除dist文件夾下的所有內容]
}
復制代碼- 更多的有關于CleanWebpackPlugin的配置見文檔
Entry與Output的基礎配置
- 需求:打包多個入口文件,對應的在出口的配置中注意命名filename避免出口文件名字沖突----使用占位符)來確保每個文件具有唯一的名稱
- 需求:打包后的文件,作為后端的接口文件,靜態資源需要上傳到cdn,在output中進行配置,提前加入cdn的地址。在編譯時,如果不知道publicPath的地址,可以留空,在入口起點文件運行時動態設置。__webpack_public_path__ = myRuntimePublicPath
module.exports = {mode:
'development',entry: {main:
'./src/index.js',sub:
'./src/index.js'},plugins: [new HtmlWebpackPlugin({template:
'src/index.html'}), new CleanWebpackPlugin([
'dist'])],output: {publicPath:
'http://cdn.com.cn', //加入cdn地址filename:
'[name].js',path: path.resolve(__dirname,
'dist')}
}
復制代碼SourceMap的配置
SourceMap是一個映射關系,打包文件和源文件的映射關系,用于開發者的調試。
在devtool中進行設置:devtool: 'source-map'打包速度會降低,在dist里面會有map映射文件
常用設置devtool說明:
- none:在開發者模式下,默認開啟sourcemap,將其關閉
- inline前綴:不單獨生成map文件,把對應的map文件以base64的形式直接打包到js文件。
- cheap前綴:sourcemap和打包后的js同行顯示,并沒有映射到列忽略源自 loader 的 source。 map,并且僅顯示轉譯后的代碼,所以打包速度相對來說較快。代碼出錯提示不用精確顯示第幾行的第幾個字符出錯,只顯示第幾行出錯,會提高一些性能,
- moudle前綴:不僅映射業務代碼,還會包括loader、第三方模塊的錯誤。
- eval前綴:打包速度最快。
development環境推薦使用: devtool: 'cheap-module-eval-source-map'
production環境推薦使用: devtool: 'cheap-module-source-map'
使用WebpackDevServer提升開發效率
場景:每次在src里編寫完代碼都需要手動重新運行 npm run bundle,如何自動解決?
-安裝:npm install webpack-dev-server –D
contentBase :配置開發服務運行時的文件根目錄open :自動打開瀏覽器host:開發服務器監聽的主機地址compress :開發服務器是否啟動gzip等壓縮port:開發服務器監聽的端口- 在 webpack.config.js 中,加 devServer
const path = require(
'path');
const HtmlWebpackPlugin = require(
'html-webpack-plugin');
const CleanWebpackPlugin = require(
'clean-webpack-plugin');module.exports = {mode:
'development',devtool:
'cheap-module-eval-source-map',devServer: {contentBase:
'./dist',open:
true,port: 8080proxy:{//配置跨域,訪問的域名會被代理到本地的3000端口
'/api':
'http://localhost:3000'}}
}
復制代碼{
"name":
"banggan",
"version":
"1.0.0",
"description":
"",
"main":
"index.js",
"scripts": {
"bundle":
"webpack",
"watch":
"webpack --watch",
"start":
"webpack-dev-server",},
}
復制代碼如何實現自己寫一個類似webpackdevserver的工具
- 在package.json 中配置 創建一個新的指令,npm run server運行自己寫的類似webpackdevserver的工具
{
"name":
"banggan",
"version":
"1.0.0",
"description":
"",
"main":
"index.js",
"scripts": {
"bundle":
"webpack",
"watch":
"webpack --watch",
"start":
"webpack-dev-server",
"server" :
"node server.js" },
}
復制代碼- 安裝express:npm install express webpack-dev-middleware -D
- 在根目錄創建一個server.js
- 在node中直接使用webpack:webpack(config)
const express = require(
'express'); //引入express
const webpack = require(
'webpack');//引入webpack
const webpackDevMiddleware = require(
'webpack-dev-middleware');
const config = require(
'./webpack.config.js');//引入配置文件const complier = webpack(config); //編譯一次嗎,打包一次代碼
const app = express();//創建express實例app.use(webpackDevMiddleware(complier, {}));app.listen(3000, () => {//監聽3000端口console.log(
'server is running');
});
復制代碼Hot Module Replacement熱模塊更新
module.exports = {mode:
'development',devtool:
'cheap-module-eval-source-map',devServer: {contentBase:
'./dist',open:
true,port: 8080,hot:
true,//開啟熱更新功能hotOnly:
true//如果html功能沒有實現,也不讓瀏覽器刷新},plugins: [new HtmlWebpackPlugin({template:
'src/index.html'}), new CleanWebpackPlugin([
'dist']),new webpack.HotModuleReplacementPlugin()//使用熱模塊插件],
}
復制代碼- 在main.js文件中,使用 HotModuleReplacementPlugin 啟用模塊的熱替換功能。接口暴露在moudle.hot屬性下面
//如果模塊啟用了HMR,就可以用 module.hot.accept(),監聽模塊的更新。
if (module.hot) {module.hot.accept(
'./library.js',
function() {// 使用更新過的 library 模塊執行某些操作...})
}
復制代碼//拒絕給定依賴模塊的更新,使用
'decline' 方法強制更新失敗。
module.hot.decline(dependencies // 可以是一個字符串或字符串數組
)
復制代碼 注意:引入css文件時,用框架Vue,React 時,不需要寫 module.hot.accept(),因為在使用css-loader,vue-loader,babel-preset時,均配置好了HMR,不需要自己重新寫 如果文件沒有內置HMR,需要自己手動寫監聽模塊更新代碼
結合Bable處理ES6語法
- 場景:代碼中含有ES6/ES7的代碼,為了讓低版本的瀏覽器兼容代碼,需要使用Bable進行轉換
- 安裝:Bable官網
//preset-env語法轉換
npm install babel-loader @babel/core @babel/preset-env -D
//兼容低版本瀏覽器的語法,函數的補充
npm install --save @babel/polyfill
復制代碼- 在 webpack.config.js 中,添加配置
module: {rules: [{
test: /\.js$/,exclude: /node_modules/, //排除在外:在node_modules中的js,babel-loader不生效loader:
"babel-loader" ,options:{
"presets": [[
"@babel/preset-env",{targets: {edge:
"17",firefox:
"60",chrome:
"67",safari:
"11.1",},//運行在大于**版本的瀏覽器上,,已經支持es6的高瀏覽器不需要轉換為es5useBuiltIns:
'usage' //按需添加polyfill,把業務代碼中的新語法新函數都轉成低版本瀏覽器兼容的}]]}}]
}
復制代碼- 在src目錄下的index.js中頂部位置導入import "@babel/polyfill";
注意如果不是打包業務代碼,而是寫的類庫、或者z組件庫的時候不能使用@babel/polyfill實現,因為會導致聲明的變量變成全局變量,污染全局環境。使用plugin-transform-runtime實現
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
npm install --save @babel/runtime-corejs2
復制代碼- 在 webpack.config.js 中,添加配置
module: {rules: [{
test: /\.js$/,exclude: /node_modules/,loader:
"babel-loader" ,options:{
"plugins": [[
"@babel/plugin-transform-runtime",{
"corejs": 2,
"helpers":
true,
"regenerator":
true,
"useESModules":
false}]]}}]
}
復制代碼由于babel配置的內容較多,官網推薦在根目錄下創建屬于babel的配置文件.babelrc文件
由于babel需要配置的內容非常多,我們需要在項目根目錄下創建一個 .babelrc 文件。 就不需要在 webpack.config.js 中寫 babel 的配置了。 在 .babelrc 中:
{
"plugins": [[
"@babel/plugin-transform-runtime", {
"corejs": 2,
"helpers":
true,
"regenerator":
true,
"useESModules":
false}]]
}
復制代碼總結
module.exports = {mode:
'development', //開發環境進行打包,打包的代碼不會壓縮devtool:
'cheap-module-eval-source-map',//不帶列信息,只對業務代碼進行sourcemap的生成 entry: {//配置入口文件main:
'./src/index.js'},devServer: {//配置webpack,開發環境的調試contentBase:
'./dist',//啟動服務器的目錄open:
true,//打開新的端口號8080port: 8080,hot:
true,//打開熱替換功能hotOnly:
true},module: {//對不同的文件進行打包規則rules: [{
test: /\.js$/, //對js文件的babel-loader打包,其配置在.babelrc文件中exclude: /node_modules/, //排除在外:在node_modules中的js,babel-loader不生效loader:
'babel-loader',}, {
test: /\.(jpg|png|gif)$/,//對圖片進行打包use: {loader:
'url-loader',options: {name:
'[name]_[hash].[ext]',outputPath:
'images/',
limit: 10240//小于10240以base64的形式進行打包}} }, {
test: /\.(eot|ttf|svg)$/,//字體文件的打包use: {loader:
'file-loader'} }, {
test: /\.scss$/,//scss文件的打包,先用postcss-loader,在用sass-loader進行解析,最后css-loader進行掛載use: [
'style-loader', {loader:
'css-loader',options: {importLoaders: 2}},
'sass-loader',
'postcss-loader']}, {
test: /\.css$/,//css文件的打包,沒有sass-loader的解析use: [
'style-loader',
'css-loader',
'postcss-loader']}]},plugins: [new HtmlWebpackPlugin({template:
'src/index.html'}), new CleanWebpackPlugin([
'dist']),//自動清空上一次打包new webpack.HotModuleReplacementPlugin()//熱替換插件],output: {//出口文件filename:
'[name].js',path: path.resolve(__dirname,
'dist')}
}
復制代碼
總結
以上是生活随笔為你收集整理的Webpack核心概念解析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。