您好,登錄后才能下訂單哦!
怎么在vue-cli中對webpack進(jìn)行配置?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
版本號
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配置
主要對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)出目錄的絕對路徑 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ǎo)入模塊時不帶拓展名 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是對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是對loader做額外的選項(xiàng)配置 limit: 10000, //圖片小于10000字節(jié)時以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é)的時候處理方式 name: utils.assetsPath('fonts/[name].[hash:7].[ext]') //文件名為name.7位hash值.拓展名 } } ] }
注: 關(guān)于query 僅由于兼容性原因而存在。請使用 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ù)組中保存的是針對各類型的樣式文件的處理方式 var loaders = exports.cssLoaders(options) // 調(diào)用cssLoaders方法返回各類型的樣式對象(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),用來返回針對各類型的樣式文件的處理方式,具體實(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組成一個對象 sourceMap: options.sourceMap }) }) } if (options.extract) { // 如果傳入的options存在extract且為true return ExtractTextPlugin.extract({ //ExtractTextPlugin分離js中引入的css文件 use: loaders, //處理的loader fallback: 'vue-style-loader' //沒有被提取分離時使用的loader }) } else { return ['vue-style-loader'].concat(loaders) } } return { //返回css類型對應(yīng)的loader組成的對象 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({ // 編譯時配置的全局變量 'process.env': config.dev.env //當(dāng)前環(huán)境為開發(fā)環(huán)境 }), new webpack.HotModuleReplacementPlugin(), //熱更新插件 new webpack.NoEmitOnErrorPlugin(), //不觸發(fā)錯誤,即編譯后運(yùn)行的包正常運(yùn)行 new HtmlWebpackPlugin({ //自動生成html文件,比如編譯后文件的引入 filename: 'index.html', //生成的文件名 template: 'index.html', //模板 inject: true }), new FriendlyErrorsPlugin() //友好的錯誤提示 ]
webpack.prod.conf.js
生產(chǎn)環(huán)境下的webpack配置,通過merge方法合并webpack.base.conf.js基礎(chǔ)配置
module的處理,主要是針對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ù)問題(多個文件引入同一css文件) new OptimizeCSSPlugin(), //生成html的插件,引入css文件和js文件 new HtmlWebpackPlugin({ filename: config.build.index, //生成的html的文件名 template: 'index.html', //依據(jù)的模板 inject: true, //注入的js文件將會被放在body標(biāo)簽中,當(dāng)值為'head'時,將被放在head標(biāo)簽中 minify: { //壓縮配置 removeComments: true, //刪除html中的注釋代碼 collapseWhitespace: true, //刪除html中的空白符 removeAttributeQuotes: true //刪除html元素中屬性的引號 }, 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)分離了第三方庫,每次修改編譯都會改變vendor的hash值,導(dǎo)致瀏覽器緩存失效。原因是vendor包含了webpack在打包過程中會產(chǎn)生一些運(yùn)行時代碼,運(yùn)行時代碼中實(shí)際上保存了打包后的文件名。當(dāng)修改業(yè)務(wù)代碼時,業(yè)務(wù)代碼的js文件的hash值必然會改變。一旦改變必然會導(dǎo)致vendor變化。vendor變化會導(dǎo)致其hash值變化。 //下面主要是將運(yùn)行時代碼提取到單獨(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壓縮 //引入壓縮文件的組件,該插件會對生成的文件進(jìn)行壓縮,生成一個.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á)式的文件會被壓縮 '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), threshold: 10240, //資源文件大于10240B=10kB時會被壓縮 minRatio: 0.8 //最小壓縮比達(dá)到0.8時才會被壓縮 }) ) }
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í)際上會運(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 //端口號 var autoOpenBrowser = !!config.dev.autoOpenBrowser //是否自動打開瀏覽器 var proxyTable = config.dev.proxyTable //http的代理url var app = express() //啟動express var compiler = webpack(webpackConfig) //webpack編譯 //webpack-dev-middleware的作用 //1.將編譯后的生成的靜態(tài)文件放在內(nèi)存中,所以在npm run dev后磁盤上不會生成文件 //2.當(dāng)文件改變時,會自動編譯。 //3.當(dāng)在編譯過程中請求某個資源時,webpack-dev-server不會讓這個請求失敗,而是會一直阻塞它,直到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無刷新更新的時機(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() }) }) //將代理請求的配置應(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') }) //啟動express服務(wù) module.exports = app.listen(port, function (err) { if (err) { console.log(err) return } // 滿足條件則自動打開瀏覽器 if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { opn(uri) } })
npm run build
由于package.json中的配置,運(yùn)行此命令后會執(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') }) })
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。