vue-cli中的webpack配置詳解
版本號(hào)
- vue-cli 2.8.1 (終端通過vue -V 可查看)
- vue 2.2.2
- webpack 2.2.1
目錄結(jié)構(gòu)
├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server.js │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ └── Hello.vue │ └── main.js └── static
webpack配置
主要對(duì)build目錄下的webpack配置做詳細(xì)分析
webpack.base.conf.js
入口文件entry
entry: {
app: '.src/main.js'
}
輸出文件output
config的配置在config/index.js文件中
output: {
path: config.build.assetsRoot, //導(dǎo)出目錄的絕對(duì)路徑
filename: '[name].js', //導(dǎo)出文件的文件名
publicPath: process.env.NODE_ENV === 'production'? config.build.assetsPublicPath : config.dev.assetsPublicPath //生產(chǎn)模式或開發(fā)模式下html、js等文件內(nèi)部引用的公共路徑
}
文件解析resolve
主要設(shè)置模塊如何被解析。
resolve: {
extensions: ['.js', '.vue', '.json'], //自動(dòng)解析確定的拓展名,使導(dǎo)入模塊時(shí)不帶拓展名
alias: { // 創(chuàng)建import或require的別名
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
}
}
模塊解析module
如何處理項(xiàng)目不同類型的模塊。
module: {
rules: [
{
test: /\.vue$/, // vue文件后綴
loader: 'vue-loader', //使用vue-loader處理
options: vueLoaderConfig //options是對(duì)vue-loader做的額外選項(xiàng)配置
},
{
test: /\.js$/, // js文件后綴
loader: 'babel-loader', //使用babel-loader處理
include: [resolve('src'), resolve('test')] //必須處理包含src和test文件夾
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, //圖片后綴
loader: 'url-loader', //使用url-loader處理
query: { // query是對(duì)loader做額外的選項(xiàng)配置
limit: 10000, //圖片小于10000字節(jié)時(shí)以base64的方式引用
name: utils.assetsPath('img/[name].[hash:7].[ext]') //文件名為name.7位hash值.拓展名
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, //字體文件
loader: 'url-loader', //使用url-loader處理
query: {
limit: 10000, //字體文件小于1000字節(jié)的時(shí)候處理方式
name: utils.assetsPath('fonts/[name].[hash:7].[ext]') //文件名為name.7位hash值.拓展名
}
}
]
}
注: 關(guān)于query 僅由于兼容性原因而存在。請(qǐng)使用 options 代替。
webpack.dev.conf.js
開發(fā)環(huán)境下的webpack配置,通過merge方法合并webpack.base.conf.js基礎(chǔ)配置
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
module.exports = merge(baseWebpackConfig, {})
模塊配置
module: {
//通過傳入一些配置來獲取rules配置,此處傳入了sourceMap: false,表示不生成sourceMap
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
}
在util.styleLoaders中的配置如下
exports.styleLoaders = function (options) {
var output = [] //定義返回的數(shù)組,數(shù)組中保存的是針對(duì)各類型的樣式文件的處理方式
var loaders = exports.cssLoaders(options) // 調(diào)用cssLoaders方法返回各類型的樣式對(duì)象(css: loader)
for (var extension in loaders) { //循環(huán)遍歷loaders
var loader = loaders[extension] //根據(jù)遍歷獲得的key(extension)來得到value(loader)
output.push({ //
test: new RegExp('\\.' + extension + '$'), // 處理的文件類型
use: loader //用loader來處理,loader來自loaders[extension]
})
}
return output
}
上面的代碼中調(diào)用了exports.cssLoaders(options),用來返回針對(duì)各類型的樣式文件的處理方式,具體實(shí)現(xiàn)如下
exports.cssLoaders = function (options) {
options = options || {}
var cssLoader = {
loader: 'css-loader',
options: { //options是loader的選項(xiàng)配置
minimize: process.env.NODE_ENV === 'production', //生成環(huán)境下壓縮文件
sourceMap: options.sourceMap //根據(jù)參數(shù)是否生成sourceMap文件
}
}
function generateLoaders (loader, loaderOptions) { //生成loader
var loaders = [cssLoader] // 默認(rèn)是css-loader
if (loader) { // 如果參數(shù)loader存在
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, { //將loaderOptions和sourceMap組成一個(gè)對(duì)象
sourceMap: options.sourceMap
})
})
}
if (options.extract) { // 如果傳入的options存在extract且為true
return ExtractTextPlugin.extract({ //ExtractTextPlugin分離js中引入的css文件
use: loaders, //處理的loader
fallback: 'vue-style-loader' //沒有被提取分離時(shí)使用的loader
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
return { //返回css類型對(duì)應(yīng)的loader組成的對(duì)象 generateLoaders()來生成loader
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
插件配置
plugins: [
new webpack.DefinePlugin({ // 編譯時(shí)配置的全局變量
'process.env': config.dev.env //當(dāng)前環(huán)境為開發(fā)環(huán)境
}),
new webpack.HotModuleReplacementPlugin(), //熱更新插件
new webpack.NoEmitOnErrorPlugin(), //不觸發(fā)錯(cuò)誤,即編譯后運(yùn)行的包正常運(yùn)行
new HtmlWebpackPlugin({ //自動(dòng)生成html文件,比如編譯后文件的引入
filename: 'index.html', //生成的文件名
template: 'index.html', //模板
inject: true
}),
new FriendlyErrorsPlugin() //友好的錯(cuò)誤提示
]
webpack.prod.conf.js
生產(chǎn)環(huán)境下的webpack配置,通過merge方法合并webpack.base.conf.js基礎(chǔ)配置
module的處理,主要是針對(duì)css的處理
同樣的此處調(diào)用了utils.styleLoaders
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
}
輸出文件output
output: {
//導(dǎo)出文件目錄
path: config.build.assetsRoot,
//導(dǎo)出的文件名
filename: utils.assetsPath('js/[name].[chunkhash].js'),
//非入口文件的文件名,而又需要被打包出來的文件命名配置,如按需加載的模塊
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
}
插件plugins
var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var env = config.build.env
plugins: [
new webpack.DefinePlugin({
'process.env': env //配置全局環(huán)境為生產(chǎn)環(huán)境
}),
new webpack.optimize.UglifyJsPlugin({ //js文件壓縮插件
compress: { //壓縮配置
warnings: false // 不顯示警告
},
sourceMap: true //生成sourceMap文件
}),
new ExtractTextPlugin({ //將js中引入的css分離的插件
filename: utils.assetsPath('css/[name].[contenthash].css') //分離出的css文件名
}),
//壓縮提取出的css,并解決ExtractTextPlugin分離出的js重復(fù)問題(多個(gè)文件引入同一css文件)
new OptimizeCSSPlugin(),
//生成html的插件,引入css文件和js文件
new HtmlWebpackPlugin({
filename: config.build.index, //生成的html的文件名
template: 'index.html', //依據(jù)的模板
inject: true, //注入的js文件將會(huì)被放在body標(biāo)簽中,當(dāng)值為'head'時(shí),將被放在head標(biāo)簽中
minify: { //壓縮配置
removeComments: true, //刪除html中的注釋代碼
collapseWhitespace: true, //刪除html中的空白符
removeAttributeQuotes: true //刪除html元素中屬性的引號(hào)
},
chunksSortMode: 'dependency' //按dependency的順序引入
}),
//分離公共js到vendor中
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', //文件名
minChunks: functions(module, count) { // 聲明公共的模塊來自node_modules文件夾
return (module.resource && /\.js$/.test(module.resource) && module,resource.indexOf(path.join(__dirname, '../node_modules')) === 0)
}
}),
//上面雖然已經(jīng)分離了第三方庫,每次修改編譯都會(huì)改變vendor的hash值,導(dǎo)致瀏覽器緩存失效。原因是vendor包含了webpack在打包過程中會(huì)產(chǎn)生一些運(yùn)行時(shí)代碼,運(yùn)行時(shí)代碼中實(shí)際上保存了打包后的文件名。當(dāng)修改業(yè)務(wù)代碼時(shí),業(yè)務(wù)代碼的js文件的hash值必然會(huì)改變。一旦改變必然會(huì)導(dǎo)致vendor變化。vendor變化會(huì)導(dǎo)致其hash值變化。
//下面主要是將運(yùn)行時(shí)代碼提取到單獨(dú)的manifest文件中,防止其影響vendor.js
new webpack.optimize.CommonsChunkPlugin({
name: 'mainifest',
chunks: ['vendor']
}),
// 復(fù)制靜態(tài)資源,將static文件內(nèi)的內(nèi)容復(fù)制到指定文件夾
new CopyWebpackPlugin([{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*'] //忽視.*文件
}])
]
額外配置
if (config.build.productionGzip) { //配置文件開啟了gzip壓縮
//引入壓縮文件的組件,該插件會(huì)對(duì)生成的文件進(jìn)行壓縮,生成一個(gè).gz文件
var CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]', //目標(biāo)文件名
algorithm: 'gzip', //使用gzip壓縮
test: new RegExp( //滿足正則表達(dá)式的文件會(huì)被壓縮
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240, //資源文件大于10240B=10kB時(shí)會(huì)被壓縮
minRatio: 0.8 //最小壓縮比達(dá)到0.8時(shí)才會(huì)被壓縮
})
)
}
npm run dev
有了上面的配置之后,下面看看運(yùn)行命令npm run dev發(fā)生了什么
在package.json文件中定義了dev運(yùn)行的腳本
"scripts": {
"dev": "node build/dev-server.js",
"build": "node build/build.js"
},
當(dāng)運(yùn)行npm run dev命令時(shí),實(shí)際上會(huì)運(yùn)行dev-server.js文件
該文件以express作為后端框架
// nodejs環(huán)境配置
var config = require('../config')
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}
var opn = require('opn') //強(qiáng)制打開瀏覽器
var path = require('path')
var express = require('express')
var webpack = require('webpack')
var proxyMiddleware = require('http-proxy-middleware') //使用代理的中間件
var webpackConfig = require('./webpack.dev.conf') //webpack的配置
var port = process.env.PORT || config.dev.port //端口號(hào)
var autoOpenBrowser = !!config.dev.autoOpenBrowser //是否自動(dòng)打開瀏覽器
var proxyTable = config.dev.proxyTable //http的代理url
var app = express() //啟動(dòng)express
var compiler = webpack(webpackConfig) //webpack編譯
//webpack-dev-middleware的作用
//1.將編譯后的生成的靜態(tài)文件放在內(nèi)存中,所以在npm run dev后磁盤上不會(huì)生成文件
//2.當(dāng)文件改變時(shí),會(huì)自動(dòng)編譯。
//3.當(dāng)在編譯過程中請(qǐng)求某個(gè)資源時(shí),webpack-dev-server不會(huì)讓這個(gè)請(qǐng)求失敗,而是會(huì)一直阻塞它,直到webpack編譯完畢
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: true
})
//webpack-hot-middleware的作用就是實(shí)現(xiàn)瀏覽器的無刷新更新
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
log: () => {}
})
//聲明hotMiddleware無刷新更新的時(shí)機(jī):html-webpack-plugin 的template更改之后
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})
//將代理請(qǐng)求的配置應(yīng)用到express服務(wù)上
Object.keys(proxyTable).forEach(function (context) {
var options = proxyTable[context]
if (typeof options === 'string') {
options = { target: options }
}
app.use(proxyMiddleware(options.filter || context, options))
})
//使用connect-history-api-fallback匹配資源
//如果不匹配就可以重定向到指定地址
app.use(require('connect-history-api-fallback')())
// 應(yīng)用devMiddleware中間件
app.use(devMiddleware)
// 應(yīng)用hotMiddleware中間件
app.use(hotMiddleware)
// 配置express靜態(tài)資源目錄
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static('./static'))
var uri = 'http://localhost:' + port
//編譯成功后打印uri
devMiddleware.waitUntilValid(function () {
console.log('> Listening at ' + uri + '\n')
})
//啟動(dòng)express服務(wù)
module.exports = app.listen(port, function (err) {
if (err) {
console.log(err)
return
}
// 滿足條件則自動(dòng)打開瀏覽器
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
opn(uri)
}
})
npm run build
由于package.json中的配置,運(yùn)行此命令后會(huì)執(zhí)行build.js文件
process.env.NODE_ENV = 'production' //設(shè)置當(dāng)前環(huán)境為production
var ora = require('ora') //終端顯示的轉(zhuǎn)輪loading
var rm = require('rimraf') //node環(huán)境下rm -rf的命令庫
var path = require('path') //文件路徑處理庫
var chalk = require('chalk') //終端顯示帶顏色的文字
var webpack = require('webpack')
var config = require('../config')
var webpackConfig = require('./webpack.prod.conf') //生產(chǎn)環(huán)境下的webpack配置
// 在終端顯示ora庫的loading效果
var spinner = ora('building for production...')
spinner.start()
// 刪除已編譯文件
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
//在刪除完成的回調(diào)函數(shù)中開始編譯
webpack(webpackConfig, function (err, stats) {
spinner.stop() //停止loading
if (err) throw err
// 在編譯完成的回調(diào)函數(shù)中,在終端輸出編譯的文件
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n')
})
})
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue路由的模塊自動(dòng)化與統(tǒng)一加載實(shí)現(xiàn)
這篇文章主要介紹了Vue路由的模塊自動(dòng)化與統(tǒng)一加載實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
如何使用Nginx將前端Vue項(xiàng)目部署到云服務(wù)器
記錄使用Nginx將純前端的Vue3項(xiàng)目部署到阿里云服務(wù)器(Ubuntu?22.04)上,包含通過Nginx代理實(shí)現(xiàn)跨域請(qǐng)求、以及個(gè)人踩坑記錄,感興趣的朋友一起看看吧2024-04-04
Vue結(jié)合echarts實(shí)現(xiàn)繪制水滴圖
這篇文章主要為大家詳細(xì)介紹了Vue如何結(jié)合echarts實(shí)現(xiàn)水滴圖的繪制,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-07-07
vant的picker組件設(shè)置文字超長(zhǎng)滾動(dòng)方式
這篇文章主要介紹了vant的picker組件設(shè)置文字超長(zhǎng)滾動(dòng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
淺談vue項(xiàng)目利用Hbuilder打包成APP流程,以及遇到的坑
這篇文章主要介紹了淺談vue項(xiàng)目利用Hbuilder打包成APP流程,以及遇到的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
buildAdmin開源項(xiàng)目引入四種圖標(biāo)方式詳解
這篇文章主要為大家介紹了buildAdmin開源項(xiàng)目引入四種圖標(biāo)方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
vue3使用useDialog實(shí)現(xiàn)對(duì)話框的示例代碼
在日常開發(fā)中,彈窗是常見的一個(gè)功能,本文主要介紹了vue3使用useDialog實(shí)現(xiàn)對(duì)話框的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01

