使用過 vue 進行項目開發的同窗,必定知道或者使用過 vue-cli 腳手架,他可以很好的搭建項目結構和工程,讓咱們可以把足夠的精力放在業務開發上。也正是由於這樣,不少時候咱們會由於項目工期短等緣由來不及或則不會刻意去了解項目工程配置,咱們今天不去介紹腳手架的使用,咱們去了解下腳手架爲咱們建立好的打包工程是怎麼作的。javascript
├── build --------------------------------- webpack相關配置文件 │ ├── build.js --------------------------webpack打包配置文件 │ ├── check-versions.js ------------------------------ 檢查npm,nodejs版本 │ ├── logo.png ---------------------------------- 項目 logo │ ├── utils.js --------------------------------------- 配置資源路徑,配置css加載器 │ ├── vue-loader.conf.js ----------------------------- 配置css加載器等 │ ├── webpack.base.conf.js --------------------------- webpack基本配置 │ ├── webpack.dev.conf.js ---------------------------- 用於開發的webpack設置 │ ├── webpack.prod.conf.js --------------------------- 用於打包的webpack設置 ├── config ---------------------------------- 配置文件 ├── index.js ------------------------------ 開發和生產環境配置文件 ├── node_modules ---------------------------- 存放依賴的目錄 ├── src ------------------------------------- 源碼 │ ├── assets ------------------------------ 靜態文件 │ ├── components -------------------------- 組件 │ ├── main.js ----------------------------- 主js │ ├── App.vue ----------------------------- 項目入口組件 │ ├── router ------------------------------ 路由 ├── package.json ---------------------------- node配置文件 ├── .babelrc--------------------------------- babel配置文件 ├── .editorconfig---------------------------- 編輯器配置 ├── .gitignore------------------------------- 配置git可忽略的文件
在看項目配置文件以前,咱們先了解下 webpack 幾個經常使用的工具和插件,若是你已經十分熟悉,你能夠跳過這一小節,直接去看,配置文件解析
path 是 node.js 中的一個模塊,用於處理目錄的對象,提升開發效css
經常使用方法: path.join(): 用於鏈接路徑。該方法的主要用途在於,會正確使用當前系統的路徑分隔符,Unix 系統是 」/「,Windows系統是 」\「 path.resolve() 用於將相對路徑轉爲絕對路徑 常使用的文件路徑 __dirname: 老是返回被執行的 js 所在文件夾的絕對路徑 __filename: 老是返回被執行的 js 的絕對路徑 process.cwd(): 老是返回運行 node 命令時所在的文件夾的絕對路徑
process對象是Node的一個全局對象,提供當前Node進程的信息。html
process 對象提供一系列屬性,用於返回系統信息 process.argv:返回當前進程的命令行參數數組。 process.env:返回一個對象,成員爲當前Shell的環境變量,好比process.env.HOME process.pid:當前進程的進程號
簡單說,Source map就是一個信息文件,裏面儲存着位置信息。也就是說,轉換後的代碼的每個位置,所對應的轉換前的位置。有了它,出錯的時候,debug 工具將直接顯示原始代碼,而不是轉換後的代碼。這無疑給開發者帶來了很大方便。webpack 的 devtool裏有 7種 SourceMap 模式vue
模式 | 解釋 |
---|---|
eval | 每一個 module 會封裝到 eval 裏包裹起來執行,而且會在末尾追加註釋 //@ sourceURL |
source-map | 生成一個 SourceMap 文件. |
hidden-source-map | 和 source-map 同樣,但不會在 bundle 末尾追加註釋. |
inline-source-map | 生成一個 DataUrl 形式的 SourceMap 文件. |
eval-source-map | 每一個 module 會經過 eval() 來執行,而且生成一個 DataUrl 形式的 SourceMap . |
cheap-source-map | 生成一個沒有列信息(column-mappings)的 SourceMaps 文件,不包含 loader 的 sourcemap(譬如 babel 的 sourcemap) |
cheap-module-source-map | 生成一個沒有列信息(column-mappings)的 SourceMaps 文件,同時 loader 的 sourcemap 也被簡化爲只包含對應行的。 |
開發環境(development)和生產環境(production)的構建目標差別很大。在開發環境中,咱們須要具備強大的、具備實時從新加載(live reloading)或熱模塊替換(hot module replacement)能力的 source map 和 localhost server。而在生產環境中,咱們的目標則轉向於關注更小的 bundle,更輕量的 source map,以及更優化的資源,以改善加載時間。因爲要遵循邏輯分離,咱們一般建議爲每一個環境編寫彼此獨立的 webpack 配置。通用的配置部分,咱們抽象出一個公共文件,經過 webpack-merge 工具的「通用」配置,咱們沒必要在環境特定的配置中重複代碼。java
ExtractTextWebpackPlugin 插件一般用來作樣式文件的分離,被分離的文件不會被內嵌到 JS bundle 中,而會被放到一個單獨的文件中,在樣式文件比較大的時候,可以提早樣式的加載,配置示例以下node
const ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { module: { rules: [ { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader" }) }] }, plugins: [ new ExtractTextPlugin("styles.css"), ] }
它會將全部的入口 chunk(entry chunks)中引用的 *.css,移動到獨立分離的 CSS 文件。所以,你的樣式將再也不內嵌到 JS bundle 中,而是會放到一個單獨的 CSS 文件(即 styles.css)當中。 若是你的樣式文件大小較大,這會作更快提早加載,由於 CSS bundle 會跟 JS bundle 並行加載。webpack
若是你有多個 webpack 入口點, 他們都會在生成的HTML文件中的 script 標籤內。若是你有任何 CSS assets 在 webpack 的輸出中(例如, 利用ExtractTextPlugin提取CSS), 那麼這些將被包含在HTML head中的<link>標籤內。一般在開發中,咱們爲了不 CDN 和瀏覽器的緩存一般會個輸出文件 bundle.js 加上一個hash 值例如 [hash].bundle.js
,使用 html-webpack-plugin 可以在建立新的 html 文件的時候將咱們把帶有哈希值的 bundle.js 引用到 html 文件.git
用來優化從腳本里提煉出來的 css ,配置示例以下web
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { module: { rules: [ { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') } ] }, plugins: [ new ExtractTextPlugin('styles.css'), new OptimizeCssAssetsPlugin({ assetNameRegExp: /\.optimize\.css$/g, cssProcessor: require('cssnano'), cssProcessorOptions: { discardComments: { removeAll: true } }, canPrint: true }) ] };
CopyWebpackPlugin從插件名稱上咱們不難看出他的做用,一般用來拷貝資源,對項目文件進行歸類整合vue-cli
friendly-errors-webpack-plugin可以更好在終端看到webapck運行的警告和錯誤,提升開發體驗
UglifyjsWebpackPlugin用來壓縮 js 代碼
webpack 項目服務,咱們一般會在開發階段用來配置項目的熱刷新,服務壓縮,項目代理等,經常使用的幾個配置參數介紹以下
const config = require('../config') // config 文件裏作了用戶自定的服務參數配置 devServer: { clientLogLevel: 'warning', // 在開發攻擊的控制檯中顯示信息,便於開發調試,你能夠將參數配置成 "none" 來進行關閉 historyApiFallback: { // 當使用 HTML5 History API 時,任意的 404 響應均可能須要被替代爲 index.html rewrites: [ { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, ], }, hot: true, //啓用項目的熱刷新,即模塊熱替換特性 contentBase: false, // 告訴服務器從哪裏提供內容。只有在你想要提供靜態文件時才須要。這裏禁用,由於配置了 CopyWebpackPlugin 的使用 compress: true, host: HOST || config.dev.host, //指定使用一個域名。默認是 localhost port: PORT || config.dev.port, //指定要監聽請求的端口號: open: config.dev.autoOpenBrowser, //open 參數配置,若是配置成 true ,項目啓動後會自動打開瀏覽器 overlay: config.dev.errorOverlay //當有錯誤或則警告的時候在頁面上顯示一個全屏的遮罩提示 ? { warnings: false, errors: true } : false, publicPath: config.dev.assetsPublicPath, //此路徑下的打包文件可在瀏覽器中訪問 proxy: config.dev.proxyTable, //代理API的請求 quiet: true, //啓用 quiet 後,除了初始啓動信息以外的任何內容都不會被打印到控制檯,特別是使用了 FriendlyErrorsPlugin 插件的時候 watchOptions: { //與監視文件相關的控制選項。是否使用輪詢 poll: config.dev.poll, } },
經過了解了上面的配置,咱們應該對 webpack 的經常使用插件和工具備了必定了解,咱們來看下 vue-cli 腳手架給咱們生成的配置狀況
'use strict'
const path = require('path') // 引用項目的 path 模塊
module.exports = {
dev: {
// 路徑配置 assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: {}, // 各類開發服務配置 host: 'localhost', // 開發環境域名 能夠被 node 全局變量process.env.HOST 重寫 port: 8080, //配置開發服務端口,能夠被 node 全局變量 process.env.PORT 重寫, 須要使用未被佔用的端口 autoOpenBrowser: false, //服務啓動是否自動代開瀏覽器 errorOverlay: true, //是否在發生錯誤的時候,在頁面整屏增長一個錯誤遮罩 notifyOnErrors: true, //是否通知錯誤 ,在咱們的項目配置中和 friendly-errors-webpack-plugin 結合使用 poll: false, // 服務監聽是否輪詢操做 // 配飾是否使用 Eslint Loader 進行語法檢測 // 若是使用,在開發構建階段,會對你的代碼會進行檢測 // 檢測出來的警告和錯誤會白展現在開發工具的控制檯 useEslint: true, //進行語法檢測 // 配置是否將 eslint 語法檢測的警告和錯誤展現在頁面整屏的遮罩上 showEslintErrorsInOverlay: false, // 語法檢測的警告和錯誤不展現在遮罩上 /** * Source Maps */ // https://webpack.js.org/configuration/devtool/#development // 在上面的介紹中,咱們知道 source map 是用來將咱們構建後被轉化的代碼對應構建前的代碼,便於 debug // cheap-module-eval-source-map 和咱們介紹的 cheap-module-source-map 很相似,可是 SourceMap 會被做爲數據添加到包中 devtool: 'cheap-module-eval-source-map', // 若是你的開發工具不能進行 vue-files 的 debug ,能夠將如下設置設置成 false cacheBusting: true, cssSourceMap: true
},
build: {
// index.html 文件模板 index: path.resolve(__dirname, '../dist/index.html'), // 打包路徑配置 assetsRoot: path.resolve(__dirname, '../dist'), assetsSubDirectory: 'static', assetsPublicPath: '/', /** * Source Maps */ //生產環境 source map 配置 productionSourceMap: true, devtool: '#source-map', // 由於不少的主流服務都會 經過 gzip 壓縮過你的全部靜態資源,咱們的配置默認不開啓 gzip // 若是要設置成開啓,請先確保已經安裝好 compression-webpack-plugin 插件 productionGzip: false, productionGzipExtensions: ['js', 'css'], // 啓動 build 命令的時候,額外添加一個參數,打包後會自動生成一個分析報告文件,例如 npm run build --report ,能夠經過配置 true ,false 來關閉 bundleAnalyzerReport: process.env.npm_config_report
}
}
這個文件主要是用來檢測當前環境中的node和npm版本和咱們須要的是否一致的。
'use strict' const chalk = require('chalk') // 改變命令行中的字體顏色,大體這樣用chalk.blue('Hello world') const semver = require('semver') //是用來對特定的版本號作判斷的 const packageConfig = require('../package.json') // 項目 npm 配置文件,獲取依賴及版本信息,requrie返回的就是json對象 const shell = require('shelljs') //用來執行Unix系統命令,調用系統命令更加方便 //把cmd這個參數傳遞的值轉化成先後沒有空格的字符串,也就是版本號 function exec (cmd) { return require('child_process').execSync(cmd).toString().trim() } const versionRequirements = [ { name: 'node', currentVersion: semver.clean(process.version), // 提取進程版本信息轉化成規定格式,也就是 ' =v1.2.3 ' -> '1.2.3' 這種功能 versionRequirement: packageConfig.engines.node // package.json 的 node 的版本信息 } ] if (shell.which('npm')) { versionRequirements.push({ name: 'npm', currentVersion: exec('npm --version'), //當前的版本信息 versionRequirement: packageConfig.engines.npm //package.json 的 node 的版本信息 }) } module.exports = function () { const warnings = [] for (let i = 0; i < versionRequirements.length; i++) { const mod = versionRequirements[i] // 若是當前版本號不符合 package.json 要求的版本號,紅色表示當前版本信息,綠色表示要求的版本信息,添加到 warnings 待輸出 if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { warnings.push(mod.name + ': ' + chalk.red(mod.currentVersion) + ' should be ' + chalk.green(mod.versionRequirement) ) } } //輸出版本號不相符的提示 warnings if (warnings.length) { console.log('') console.log(chalk.yellow('To use this template, you must update following to modules:')) console.log() for (let i = 0; i < warnings.length; i++) { const warning = warnings[i] console.log(' ' + warning) } console.log() process.exit(1) } }
'use strict' //打包前判斷當先開發環境的 node 和 npm 版本和 package.json 要求的時候同樣 require('./check-versions')() process.env.NODE_ENV = 'production' const ora = require('ora') // 在用戶打包的時候可以讓用戶知道正在進行,一個加載中的樣式,轉啊轉 const rm = require('rimraf') //這個模塊是用來清除以前的打的包,由於在vue-cli中每次打包會生成不一樣的hash const path = require('path') //node 路徑模塊,便於咱們操做文件路徑 const chalk = require('chalk') //帶顏色的輸出模塊,能在控制檯中輸出不一樣的樣色 const webpack = require('webpack') //webpack 不解釋 const config = require('../config') // 項目中的配置文件,👆上面已經進行了配置介紹 const webpackConfig = require('./webpack.prod.conf') // 生產環境的配置文件 const spinner = ora('building for production...')// 實例一個打包加載中實例 spinner.start() //開始轉圈,營造一個正在打包的場景 // 刪除上一次打包的文件,刪除成功,開始按照生產環境配置進行打包 rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { if (err) throw err //開始打包,打包結束中止 spinner 轉圈,有報錯則在控制檯輸出 webpack(webpackConfig, (err, stats) => { spinner.stop() if (err) throw err // node 環境裏的輸出配置,process.stdout.write 你能夠理解成 js 裏的 console process.stdout.write(stats.toString({ colors: true, //讓打包的時候有顏色。 modules: false, //去掉內置模塊信息 children: false, // 去掉子模塊,若是你使用了 ts-loader,設置成 true 會在打包構建階段展現錯誤信息 chunks: false, // 增長包信息(設置爲 false 能容許較少的冗長輸出) chunkModules: false //去除包裏內置模塊的信息 }) + '\n\n') //打包出錯在控制檯輸出 Build failed with errors ,退出打包程序 if (stats.hasErrors()) { console.log(chalk.red(' Build failed with errors.\n')) process.exit(1) } //打包成功則輸出 Build complete 結束打包 console.log(chalk.cyan(' Build complete.\n')) console.log(chalk.yellow( ' Tip: built files are meant to be served over an HTTP server.\n' + ' Opening index.html over file:// won\'t work.\n' )) }) })
'use strict' const path = require('path') // node 路徑模塊 const utils = require('./utils') //node 內部經常使用的工具類,其中包括:格式化字符串、對象的序列化、實現對象繼承等經常使用方法 const config = require('../config') //👆上面咱們介紹的,項目配置文件 const vueLoaderConfig = require('./vue-loader.conf') //👆 上面咱們介紹的 vue 加載器配置文件 //返回當前配置文件位置是 build ,該方法放回 build/../dir 的相對路基 function resolve (dir) { return path.join(__dirname, '..', dir) } // eslint 語法檢測配置 const createLintingRule = () => ({ test: /\.(js|vue)$/, loader: 'eslint-loader', enforce: 'pre', include: [resolve('src'), resolve('test')], options: { formatter: require('eslint-friendly-formatter'), emitWarning: !config.dev.showEslintErrorsInOverlay } }) // webpack 通用配置內容 module.exports = { context: path.resolve(__dirname, '../'), // 上下文,基礎目錄,用於從配置中解析入口起點和 loader entry: { app: './src/main.js' //起點或是應用程序的起點入口。從這個起點開始,應用程序啓動執行。若是傳遞一個數組,那麼數組的每一項都會執行。 }, output: { path: config.build.assetsRoot, //輸出 bundle 的路徑 filename: '[name].js', //輸出 bundle 的名稱 publicPath: process.env.NODE_ENV === 'production' // 指定資源文件引用的目錄,例如圖片 ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, resolve: { extensions: ['.js', '.vue', '.json'], //配置模塊如何解析, alias: { // 建立應用的別名, 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } },
module: {
rules: [ //判斷配置中是否要是用 eslint 語法檢測,若是使用,就將 createLintingRule 配置對象返回 ...(config.dev.useEslint ? [createLintingRule()] : []), //👇是一些比較經常使用的加載器,及配置,不作詳細介紹了 { test: /\.vue$/, loader: 'vue-loader', options: vueLoaderConfig }, { test: /\.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] }, { test: /\.(css | scss)$/, loader: 'style-loader!css-loader!!sass-loader' }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('media/[name].[hash:7].[ext]') } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ]
},
node: {
//防止由於 vue 資源自己就自帶的 無用的 node 注入,瀏覽器兼容處理 setImmediate: false, dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty'
}
}
'use strict' const utils = require('./utils') //node 工具模塊 const webpack = require('webpack') //webpack 不解釋 const config = require('../config')//👆提到的配置文件 const merge = require('webpack-merge') // merge 工具,用來合併生產和開發環境通用的基礎 webpack 配置 const path = require('path') //node 的路徑模塊 const baseWebpackConfig = require('./webpack.base.conf') //生產和開發環境通用的基礎 webpack 配置 const CopyWebpackPlugin = require('copy-webpack-plugin') //拷貝插件 const HtmlWebpackPlugin = require('html-webpack-plugin') //動態生成 html 插件 const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') //友好的錯誤輸出插件 const portfinder = require('portfinder') //可以獲取一個可用的隨機端口號 const HOST = process.env.HOST //node 全局環境變量的主機 const PORT = process.env.PORT && Number(process.env.PORT) //node 全局環境變量的端口 //合併基礎配置加載器的配置部分 const devWebpackConfig = merge(baseWebpackConfig, { module: { // 爲 .vue 文件意外的獨立樣式文件配置加載器 rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) }, // cheap-module-eval-source-map 在開發環境中很快 devtool: config.dev.devtool, // 開發服務配置,👆 已經細講過,順便回顧一下 devServer: { clientLogLevel: 'warning', // 在開發攻擊的控制檯中顯示信息,便於開發調試,你能夠將參數配置成 "none" 來進行關閉 historyApiFallback: { // 當使用 HTML5 History API 時,任意的 404 響應均可能須要被替代爲 index.html rewrites: [ { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, ], }, hot: true, //啓用項目的熱刷新,即模塊熱替換特性 contentBase: false, // 告訴服務器從哪裏提供內容。只有在你想要提供靜態文件時才須要。這裏禁用,由於配置了 CopyWebpackPlugin 的使用 compress: true, host: HOST || config.dev.host, //指定使用一個域名。默認是 localhost port: PORT || config.dev.port, //指定要監聽請求的端口號: open: config.dev.autoOpenBrowser, //open 參數配置,若是配置成 true ,項目啓動後會自動打開瀏覽器 overlay: config.dev.errorOverlay //當有錯誤或則警告的時候在頁面上顯示一個全屏的遮罩提示 ? { warnings: false, errors: true } : false, publicPath: config.dev.assetsPublicPath, //此路徑下的打包文件可在瀏覽器中訪問 proxy: config.dev.proxyTable, //代理API的請求 quiet: true, //啓用 quiet 後,除了初始啓動信息以外的任何內容都不會被打印到控制檯,特別是使用了 FriendlyErrorsPlugin 插件的時候 watchOptions: { //與監視文件相關的控制選項。是否使用輪詢 poll: config.dev.poll, } }, plugins: [ // DefinePlugin 容許建立一個在編譯時能夠配置的全局常量。這可能會對開發模式和發佈模式的構建容許不一樣的行爲很是有用 new webpack.DefinePlugin({ 'process.env': require('../config/dev.env') }), new webpack.HotModuleReplacementPlugin(), //啓用熱替換模塊(Hot Module Replacement),也被稱爲 HMR new webpack.NamedModulesPlugin(), // 當開啓 HMR 的時候使用該插件會顯示模塊的相對路徑,建議用於開發環境 new webpack.NoEmitOnErrorsPlugin(), 在編譯出現錯誤時,使用 NoEmitOnErrorsPlugin 來跳過輸出階段 //HtmlWebpackPlugin簡化了HTML文件的建立,以便爲你的webpack包提供服務。這對於在文件名中包含每次會隨着編譯而發生變化哈希的 webpack bundle 尤爲有用 new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html', inject: true }), // 拷貝自定義的靜態資源文件 new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.dev.assetsSubDirectory, ignore: ['.*'] } ]) ] }) // 實例一個異步對象,執行 devWebpackConfig 配置編譯 module.exports = new Promise((resolve, reject) => { portfinder.basePort = process.env.PORT || config.dev.port //設置基礎端口 portfinder.getPort((err, port) => {獲取端口,輸出構建新 if (err) { reject(err) } else { // 若是進行 e2e 測試,須要發佈新端口 process.env.PORT = port // 更新 devServer 的端口 devWebpackConfig.devServer.port = port devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ compilationSuccessInfo: { messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], }, onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined })) //執行打包配置文件 resolve(devWebpackConfig) } }) })
'use strict' const path = require('path') // node 路徑模塊 const utils = require('./utils') //小工具函數 const webpack = require('webpack') // webpack 不解釋 const config = require('../config')//👆提到的配置文件 const merge = require('webpack-merge') // merge 工具,用來合併生產和開發環境通用的基礎 webpack 配置 const baseWebpackConfig = require('./webpack.base.conf')//產和開發環境通用的基礎 webpack 配置 const CopyWebpackPlugin = require('copy-webpack-plugin') //拷貝插件 const HtmlWebpackPlugin = require('html-webpack-plugin') //動態生成 html 插件 const ExtractTextPlugin = require('extract-text-webpack-plugin')//用來作文件分離的插件 const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')//優化提煉出來的css const UglifyJsPlugin = require('uglifyjs-webpack-plugin')// 壓縮 js 文件插件 //生產環境配置 const env = require('../config/prod.env') //合併基礎配置加載器的配置部分 const webpackConfig = merge(baseWebpackConfig, { //爲獨立分離出來的樣式配置加載器和source,map module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true }) }, //配置線上的 source map 便於排查問題 devtool: config.build.productionSourceMap ? config.build.devtool : false, //配置輸出,路徑,文件名 output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, plugins: [ // DefinePlugin 容許建立一個在編譯時能夠配置的全局常量。這可能會對開發模式和發佈模式的構建容許不一樣的行爲很是有用 new webpack.DefinePlugin({ 'process.env': env }), // 使用 UglifyJsPlugin 插件對 js 進行壓縮 new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false } }, //配置插件的source map sourceMap: config.build.productionSourceMap, parallel: true }), // 提取 css 到單獨的文件,分離文件異步加載,提升加載速度 new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'), //若是把 allChunks 參數設置陳 false ,就不會把css 從代碼塊中分離出來 //代碼塊加載的時候 css 會被 styles-loader 動態的加載 allChunks: true, }), //使用這個插件,從不一樣的組件中複製脫離出來,進行 css 壓縮 new OptimizeCSSPlugin({ cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: { inline: false } } : { safe: true } }), //自動生成 html 文件,一般 index.html 文件都會帶一個哈希值來清除緩存 new HtmlWebpackPlugin({ filename: config.build.index, template: 'index.html', inject: true, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }, chunksSortMode: 'dependency' }), //該插件會根據模塊的相對路徑生成一個四位數的hash做爲模塊id, 渲染模塊沒有變化的時候,id 不會變。 new webpack.HashedModuleIdsPlugin(), // 提高或者預編譯全部模塊到一個閉包中,提高你的代碼在瀏覽器中的執行速度。 new webpack.optimize.ModuleConcatenationPlugin(), // 分離渲染的js 到獨立的文件中 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks (module) { //被引用到的包會從 node_modules 中提取出來 return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) } }), new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', minChunks: Infinity }), new webpack.optimize.CommonsChunkPlugin({ name: 'app', async: 'vendor-async', children: true, minChunks: 3 }), // 拷貝自定義的靜態資源文件 new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory, ignore: ['.*'] } ]) ] }) //判斷若是配置了生產環境壓縮,是則使用插件進行壓縮 if (config.build.productionGzip) { const CompressionWebpackPlugin = require('compression-webpack-plugin') webpackConfig.plugins.push( new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp( '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), threshold: 10240, minRatio: 0.8 }) ) } //是否要生成代碼打包分析報告 if (config.build.bundleAnalyzerReport) { const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) } module.exports = webpackConfig
👆這篇文章詳細的介紹了腳手架項目的 webpack 配置,可是隻是 webpack 的一部分,還有不少內容值得咱們去探究,若是你還感興趣,能夠閱讀下面這些文章。也歡迎隨時與我進行交流,微信號:646321933