webpack--神同樣的存在。不管寫了多少次,再次相見,還是初見。有的時候開發vue項目,對尤大的vue-cli感激不盡。可是,可是,可是。。。不是本身的東西,真的很不想折騰。因此,咱們就得深刻內部,cp them us
。因此呢,就利用兩天時間,參考了一些他人的文章,查閱了一些官方的配置,就在此先稍微記錄一下。javascript
這份配置解析是基於最新版本的 vue webpack template。不過,我很是建議,先別看個人文章,本身一句一句的通讀一遍。而後再來瞅瞅,畢竟,碰撞的思惟才能創造新的發現。
vue webpack的配置文件仍是挺多的,下面是關於此配置的基本目錄結構:css
config ├── dev.env.js //dev環境變量配置 ├── index.js // dev和prod環境的一些基本配置 └── prod.env.js // prod環境變量配置 build ├── build.js // npm run build所執行的腳本 ├── check-versions.js // 檢查npm和node的版本 ├── logo.png ├── utils.js // 一些工具方法,主要用於生成cssLoader和styleLoader配置 ├── vue-loader.conf.js // vueloader的配置信息 ├── webpack.base.conf.js // dev和prod的公共配置 ├── webpack.dev.conf.js // dev環境的配置 └── webpack.prod.conf.js // prod環境的配置
下面咱們就按照以下的順序分析源碼:html
config/index.js
-> build/utils.js
-> build/vue-loader.conf.js
-> build/webpack.base.conf.js
-> build/webpack.dev.conf.js
-> build/webpack.prod.conf.js
-> build/check-versions.js
-> build/build.js
vue
config/index.js
: 一些基本屬性的配置(咱們能夠根據本身的須要來更改這些配置)'use strict' // 這個文件主要是對開發環境和生產環境的一個基本的配置 const path = require('path') module.exports = { // 開發環境的一個基本配置 dev: { // 編譯輸出的二級目錄 assetsSubDirectory: 'static', // 編譯發佈的根目錄,可配置爲資源服務器域名或者cdn域名 assetsPublicPath: '/', // 須要使用proxyTable代理的接口(能夠跨域) proxyTable: {}, // 開發時候的訪問域名。能夠經過環境變量本身設置。 host: 'localhost', // can be overwritten by process.env.HOST // 開發時候的端口。能夠經過環境變量PORT設定。若是端口被佔用了,會隨機分配一個未被使用的端口 port: 8080, // 是否自動打開瀏覽器 autoOpenBrowser: false, // 下面兩個都是瀏覽器展現錯誤的方式 // 在瀏覽器是否展現錯誤蒙層 errorOverlay: true, // 是否展現錯誤的通知 notifyOnErrors: true, // 這個是webpack-dev-servr的watchOptions的一個選項,指定webpack檢查文件的方式 // 由於webpack使用文件系統去獲取文件改變的通知。在有些狀況下,這個可能不起做用。例如,當使用NFC的時候, // vagrant也會在這方面存在不少問題,在這些狀況下,使用poll選項(以輪詢的方式去檢查文件是否改變)能夠設定爲true // 或者具體的數值,指定文件查詢的具體週期。 poll: false, // 是否使用eslint loader去檢查代碼 useEslint: true, // 若是設置爲true,在瀏覽器中,eslint的錯誤和警告會以蒙層的方式展示。 showEslintErrorsInOverlay: false, /** * Source Maps */ // source maps的格式 devtool: 'eval-source-map', // 指定是否經過在文件名稱後面添加一個查詢字符串來建立source map的緩存 cacheBusting: true, // 關閉css的source map cssSourceMap: false, }, build: { // html文件的生成的地方 index: path.resolve(__dirname, '../dist/index.html'), // 編譯生成的文件的目錄 assetsRoot: path.resolve(__dirname, '../dist'), // 編譯生成的靜態文件的目錄 assetsSubDirectory: 'static', // 編譯發佈的根目錄,可配置爲資源服務器域名或者cdn域名 assetsPublicPath: '/', /** * Source Maps */ productionSourceMap: true, devtool: '#source-map', // 是否開啓生產環境的gzip壓縮 productionGzip: false, // 開啓gzip壓縮的文件的後綴名稱 productionGzipExtensions: ['js', 'css'], // 若是這個選項是true的話,那麼則會在build後,會在瀏覽器中生成一份bundler報告 bundleAnalyzerReport: process.env.npm_config_report } }
build/utils.js
: 主要用於生成css loader和style loader的一些方法'use strict' // 引入nodejs的path模塊,用於操做路徑 const path = require('path') // 引入模板的配置文件,下面就須要去這個文件中看看有什麼基本的配置 const config = require('../config') // 提取特定文件的插件,好比把css文件提取到一個文件中去 const ExtractTextPlugin = require('extract-text-webpack-plugin') // 加載package.json文件 const packageConfig = require('../package.json') // 生成編譯輸出的二級目錄 exports.assetsPath = function (_path) { const assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory // path.posix是path模塊跨平臺的實現(不一樣平臺的路徑表示是不同的) return path.posix.join(assetsSubDirectory, _path) } // 爲不一樣的css預處理器提供一個統一的生成方式,也就是統一處理各類css類型的打包問題。 // 這個是爲在vue文件中的style中使用的css類型 exports.cssLoaders = function (options) { options = options || {} // 打包css模塊 const cssLoader = { loader: 'css-loader', options: { sourceMap: options.sourceMap } } // 編譯postcss模塊 const postcssLoader = { // 使用postcss-loader來打包postcss模塊 loader: 'postcss-loader', // 配置source map options: { sourceMap: options.sourceMap } } // 建立loader加載器字符串,結合extract text插件使用 /** * * @param {loader的名稱} loader * @param {loader對應的options配置對象} loaderOptions */ function generateLoaders (loader, loaderOptions) { // 經過usePostCSS 來標明是否使用了postcss const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] // 若是指定了具體的loader的名稱 if (loader) { // 向loaders的數組中添加該loader對應的加載器 // 一個很重要的地方就是,一個數組中的loader加載器,是從右向左執行的。 loaders.push({ // loader加載器的名稱 loader: loader + '-loader', // 對應的加載器的配置對象 options: Object.assign({}, loaderOptions, { sourceMap: options.sourceMap }) }) } // 若是明確指定了須要提取靜態文件,則使用 // ExtractTextPlugin.extract({})來包裹咱們的各類css處理器。 if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, // fallback這個選項咱們能夠這樣理解 // webpack默認會按照loaders中的加載器從右向左調用編譯各類css類型文件。若是一切順利,在loaders中的 // 各個加載器運行結束以後就會把css文件導入到規定的文件中去,若是不順利,則繼續使用vue-style-loader來處理 // css文件 fallback: 'vue-style-loader' }) } else { // 若是沒有提取行爲,則最後再使用vue-style-loader處理css return ['vue-style-loader'].concat(loaders) } } return { // css-loader css: generateLoaders(), // postcss-loader postcss: generateLoaders(), // less-loader less: generateLoaders('less'), // sass-loader 後面的選項代表sass使用的是縮進的愈發 sass: generateLoaders('sass', { indentedSyntax: true }), // scss-loader scss: generateLoaders('sass'), // stylus-loader stylus文件有兩種後綴名.stylus和styl stylus: generateLoaders('stylus'), // stylus-loader styl: generateLoaders('stylus') } } // 使用這個函數,爲那些獨立的style文件建立加載器配置。 exports.styleLoaders = function (options) { // 保存加載器配置的變量 const output = [] // 獲取全部css文件類型的loaders const loaders = exports.cssLoaders(options) for (const extension in loaders) { const loader = loaders[extension] // 生成對應的loader配置 output.push({ test: new RegExp('\\.' + extension + '$'), use: loader }) } return output } exports.createNotifierCallback = () => { // node-notifier是一個跨平臺的包,以相似瀏覽器的通知的形式展現信息。 const notifier = require('node-notifier') return (severity, errors) => { // 只展現錯誤的信息 if (severity !== 'error') return const error = errors[0] const filename = error.file && error.file.split('!').pop() // 須要展現的錯誤信息的內容 notifier.notify({ // 通知的標題 title: packageConfig.name, // 通知的主體內容 message: severity + ': ' + error.name, // 副標題 subtitle: filename || '', // 通知展現的icon icon: path.join(__dirname, 'logo.png') }) } }
build/vue-loader.conf.js
:vue-loader的一些基本配置'use strict' const utils = require('./utils') const config = require('../config') // 設置是否是生產環境 const isProduction = process.env.NODE_ENV === 'production' // 根據不一樣的環境,引入不一樣的source map配置文件 const sourceMapEnabled = isProduction ? config.build.productionSourceMap : config.dev.cssSourceMap module.exports = { // vue文件中的css loader配置 loaders: utils.cssLoaders({ sourceMap: sourceMapEnabled, // 生產環境下就會把css文件抽取到一個獨立的文件中 extract: isProduction }), // css source map文件的配置 cssSourceMap: sourceMapEnabled, // css source map文件緩存控制變量 cacheBusting: config.dev.cacheBusting, transformToRequire: { video: ['src', 'poster'], source: 'src', img: 'src', image: 'xlink:href' } }
build/weback.base.conf.js
:dev和prod環境下的公共配置'use strict' const path = require('path') const utils = require('./utils') const config = require('../config') const vueLoaderConfig = require('./vue-loader.conf') // 生成相對於根目錄的絕對路徑 function resolve (dir) { return path.join(__dirname, '..', dir) } // eslint的規則 const createLintingRule = () => ({ // 對.js和.vue結尾的文件進行eslint檢查 test: /\.(js|vue)$/, // 使用eslint-loader loader: 'eslint-loader', // enforce的值多是pre和post。其中pre有點和webpack@1中的preLoader配置含義類似。 // post和v1中的postLoader配置含義類似。表示loader的調用時機 // 這裏表示在調用其餘loader以前須要先調用這個規則進行代碼風格的檢查 enforce: 'pre', // 須要進行eslint檢查的文件的目錄存在的地方 include: [resolve('src'), resolve('test')], // eslint-loader配置過程當中須要指定的選項 options: { // 文件風格的檢查的格式化程序,這裏使用的是第三方的eslint-friendly-formatter formatter: require('eslint-friendly-formatter'), // 是否須要eslint輸出警告信息 emitWarning: !config.dev.showEslintErrorsInOverlay } }) // 下面就是webpack基本的配置信息(能夠當即成是開發環境和生產環境公共的配置) module.exports = { // webpack解析文件時候的根目錄(若是把webpack.config.js)放在了項目的根目錄下面,這個配置能夠省略 context: path.resolve(__dirname, '../'), // 指定項目的入口文件 entry: { app: './src/main.js' }, // 項目的輸出配置 output: { // 項目build的時候,生成的文件的存放路徑(這裏的路徑是../dist) path: config.build.assetsRoot, // 生成文件的名稱 filename: '[name].js', // 輸出解析文件的目錄,url 相對於 HTML 頁面(生成的html文件中,css和js等靜態文件的url前綴) publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, // 配置模塊解析時候的一些選項 resolve: { // 指定哪些類型的文件能夠引用的時候省略後綴名 extensions: ['.js', '.vue', '.json'], // 別名,在引入文件的時候可使用 alias: { 'vue$': 'vue/dist/vue.esm.js', // 能夠在引入文件的時候使用@符號引入src文件夾中的文件 '@': resolve('src'), } }, // 下面是針對具體的模塊進行的具體的配置 // 下面的配置語法採用的是version >= @2的版本 module: { // rules是一個數組,其中的每個元素都是一個對象,這個對象是針對具體類型的文件進行的配置。 rules: [ // .vue文件的配置 { // 這個屬性是一個正則表達式,用於匹配文件。這裏匹配的是.vue文件 test: /\.vue$/, // 指定該種類型文件的加載器名稱 loader: 'vue-loader', // 針對此加載器的具體配置 // 針對前面的分析,這個配置對象中包含了各類css類型文件的配置,css source map的配置 以及一些transform的配置 options: vueLoaderConfig }, { // .js文件的配置 test: /\.js$/, // js文件的處理主要使用的是babel-loader。在這裏沒有指定具體的編譯規則,babel-loader會自動 // 讀取根目錄下面的.babelrc中的babel配置用於編譯js文件 /** * { * // 使用的預設 "presets": [ // babel-preset-env: 根據你所支持的環境自動決定具體類型的babel插件 ["env", { // modules設置爲false,不會轉換module "modules": false }], // babel-preset-stage-2: 可使用全部>=stage2語法 "stage-2" ], // 使用的插件 // babel-plugin-transform-runtime: 只會對es6的語法進行轉換而不會對新的api進行轉換 // 若是須要支持新的api,請引入babel-polyfill "plugins": ["transform-runtime"] } */ loader: 'babel-loader', // 指定須要進行編譯的文件的路徑 // 這裏表示只對src和test文件夾中的文件進行編譯 include: [resolve('src'), resolve('test')] }, { // 對圖片資源進行編譯的配置 // 指定文件的類型 test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, // 使用url-loader進行文件資源的編譯 loader: 'url-loader', // url-loader的配置選項 options: { // 文件的大小小於10000字節(10kb)的時候會返回一個dataUrl 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]') } } ] }, // 這些選項用於配置polyfill或mock某些node.js全局變量和模塊。 // 這可使最初爲nodejs編寫的代碼能夠在瀏覽器端運行 node: { // 這個配置是一個對象,其中的每一個屬性都是nodejs全局變量或模塊的名稱 // prevent webpack from injecting useless setImmediate polyfill because Vue // source contains it (although only uses it if it's native). // false表示什麼都不提供。若是獲取此對象的代碼,可能會由於獲取不到此對象而觸發ReferenceError錯誤 setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client // 設置成empty則表示提供一個空對象 dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' } }
build/weboack.dev.conf.js
:dev環境的配置'use strict' // 首先引入的是一些工具方法,下面咱們就須要去util文件種看一下有哪些對應的工具方法 const utils = require('./utils') // 引入webpack模塊 const webpack = require('webpack') // 引入配置文件 // 這個配置文件中包含了一些dev和production環境的基本配置 const config = require('../config') // 引入webpack-merge模塊。這個模塊用於把多個webpack配置合併成一個配置,後面的配置會覆蓋前面的配置。 const merge = require('webpack-merge') // 引入webpack的基本設置,這個設置文件包含了開發環境和生產環境的一些公共配置 const baseWebpackConfig = require('./webpack.base.conf') // 用於生成html文件的插件 const HtmlWebpackPlugin = require('html-webpack-plugin') // 這個插件可以更好的在終端看到webpack運行時的錯誤和警告等信息。能夠提高開發體驗。 const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') // 查找一個未使用的端口 const portfinder = require('portfinder') // 獲取host環境變量,用於配置開發環境域名 const HOST = process.env.HOST // 獲取post環境變量,用於配置開發環境時候的端口號 const PORT = process.env.PORT && Number(process.env.PORT) // 開發環境的完整的配置文件, const devWebpackConfig = merge(baseWebpackConfig, { module: { // 爲那些獨立的css類型文件添加loader配置(沒有寫在vue文件的style標籤中的樣式) rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) }, // 開發環境使用'eval-source-map'模式的source map // 由於速度快 devtool: config.dev.devtool, // these devServer options should be customized in /config/index.js // 下面是對webpack-dev-server選項的基本配置,這些配置信息,咱們能夠在/config/index.js // 文件中進行自定義配置。 devServer: { // 用於配置在開發工具的控制檯中顯示的日誌級別 // 注意這個不是對bundle的錯誤和警告的配置,而是對它生成以前的消息的配置 clientLogLevel: 'warning', // 表示當使用html5的history api的時候,任意的404響應都須要被替代爲index.html historyApiFallback: true, // 啓用webpack的熱替換特性 hot: true, // 一切服務都須要使用gzip壓縮 // 能夠在js,css等文件的response header中發現有Content-Encoding:gzip響應頭 compress: true, // 指定使用一個 host。默認是 localhost // 若是但願服務器外部能夠訪問(經過咱們電腦的ip地址和端口號訪問咱們的應用) // 能夠指定0.0.0.0 host: HOST || config.dev.host, // 指定要監聽請求的端口號 port: PORT || config.dev.port, // 是否自動打開瀏覽器 open: config.dev.autoOpenBrowser, // 當編譯出現錯誤的時候,是否但願在瀏覽器中展現一個全屏的蒙層來展現錯誤信息 overlay: config.dev.errorOverlay // 表示只顯示錯誤信息而不顯示警告信息 // 若是二者都但願顯示,則把這兩項都設置爲true ? { warnings: false, errors: true } // 設置爲false則表示啥都不顯示 : false, // 指定webpack-dev-server的根目錄,這個目錄下的全部的文件都是能直接經過瀏覽器訪問的 // 推薦和output.publicPath設置爲一致 publicPath: config.dev.assetsPublicPath, // 配置代理,這樣咱們就能夠跨域訪問某些接口 // 咱們訪問的接口,若是符合這個選項的配置,就會經過代理服務器轉發咱們的請求 proxy: config.dev.proxyTable, // 啓用 quiet 後,除了初始啓動信息以外的任何內容都不會被打印到控制檯。這也意味着來自 webpack 的錯誤或警告在控制檯不可見。 quiet: true, // necessary for FriendlyErrorsPlugin // 與監視文件相關的控制選項。 watchOptions: { // 若是這個選項爲true,會以輪詢的方式檢查咱們的文件的變更,效率很差 poll: config.dev.poll, } }, plugins: [ // 建立一個在編譯時能夠配置的全局變量 new webpack.DefinePlugin({ 'process.env': require('../config/dev.env') }), // 啓用熱替換模塊 // 記住,咱們永遠不要再生產環境中使用hmr new webpack.HotModuleReplacementPlugin(), // 這個插件的主要做用就是在熱加載的時候直接返回更新文件的名稱,而不是文件的id new webpack.NamedModulesPlugin(), // 使用這個插件能夠在編譯出錯的時候來跳過輸出階段,這樣能夠確保輸出資源不會包含錯誤。 new webpack.NoEmitOnErrorsPlugin(), // 這個插件主要是生成一個html文件 new HtmlWebpackPlugin({ // 生成的html文件的名稱 filename: 'index.html', // 使用的模板的名稱 template: 'index.html', // 將全部的靜態文件都插入到body文件的末尾 inject: true }), ] }) module.exports = new Promise((resolve, reject) => { portfinder.basePort = process.env.PORT || config.dev.port // 這種獲取port的方式會返回一個promise portfinder.getPort((err, port) => { if (err) { reject(err) } else { // 把獲取到的端口號設置爲環境變量PORT的值 process.env.PORT = port // 從新設置webpack-dev-server的端口的值 devWebpackConfig.devServer.port = port // 將FriendlyErrorsPlugin添加到webpack的配置文件中 devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ // 編譯成功時候的輸出信息 compilationSuccessInfo: { messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], }, // 當編譯出錯的時候,根據config.dev.notifyOnErrors來肯定是否須要在桌面右上角顯示錯誤通知框 onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined })) // resolve咱們的配置文件 resolve(devWebpackConfig) } }) })
build/webpack.prod.conf.js
:prod環境的基本配置'use strict' // 引入path模塊 const path = require('path') // 引入工具方法 const utils = require('./utils') // 引入webpack模塊 const webpack = require('webpack') // 引入基本的配置 const config = require('../config') // 引入webpack-merge模塊 const merge = require('webpack-merge') // 引入開發環境和生產環境公共的配置 const baseWebpackConfig = require('./webpack.base.conf') // 引入copy-webpack-plugin模塊 // 這個模塊主要用於在webpack中拷貝文件和文件夾 const CopyWebpackPlugin = require('copy-webpack-plugin') // 引入html-webpack-plugin插件 // 這個插件主要是用於基於模版生成html文件的 const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入extract-text-webpack-plugin插件 // 這個插件主要是用於將入口中全部的chunk,移到獨立的分離的css文件中 const ExtractTextPlugin = require('extract-text-webpack-plugin') // 引入optimize-css-assets-webpack-plugin插件 // 這個插件主要是用於壓縮css模塊的 const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') // 引入uglifyjs-webpack-plugin插件 // 這個插件主要是用於壓縮js文件的 const UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 引入用於生產環境的一些基本變量 const env = require('../config/prod.env') // 合併公共配置和生產環境獨有的配置並返回一個用於生產環境的webpack配置文件 const webpackConfig = merge(baseWebpackConfig, { // 用於生產環境的一些loader配置 module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, // 在生產環境中使用extract選項,這樣就會把thunk中的css代碼抽離到一份獨立的css文件中去 extract: true, usePostCSS: true }) }, // 配置生產環境中使用的source map的形式。在這裏,生產環境使用的是#source map的形式 devtool: config.build.productionSourceMap ? config.build.devtool : false, output: { // build所產生的文件的存放的文件夾地址 path: config.build.assetsRoot, // build以後的文件的名稱 // 這裏[name]和[chunkhash]都是佔位符 // 其中[name]指的就是模塊的名稱 // [chunkhash]chunk內容的hash字符串,長度爲20 filename: utils.assetsPath('js/[name].[chunkhash].js'), // [id]也是一個佔位符,表示的是模塊標識符(module identifier) chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, plugins: [ // http://vuejs.github.io/vue-loader/en/workflow/production.html new webpack.DefinePlugin({ 'process.env': env }), // 壓縮javascript的插件 new UglifyJsPlugin({ // 壓縮js的時候的一些基本配置 uglifyOptions: { // 配置壓縮的行爲 compress: { // 在刪除未使用的變量等時,顯示警告信息,默認就是false warnings: false } }, // 使用 source map 將錯誤信息的位置映射到模塊(這會減慢編譯的速度) // 並且這裏不能使用cheap-source-map sourceMap: config.build.productionSourceMap, // 使用多進程並行運行和文件緩存來提升構建速度 parallel: true }), // 提取css文件到一個獨立的文件中去 new ExtractTextPlugin({ // 提取以後css文件存放的地方 // 其中[name]和[contenthash]都是佔位符 // [name]就是指模塊的名稱 // [contenthash]根據提取文件的內容生成的 hash filename: utils.assetsPath('css/[name].[contenthash].css'), // 從全部額外的 chunk(additional chunk) 提取css內容 // (默認狀況下,它僅從初始chunk(initial chunk) 中提取) // 當使用 CommonsChunkPlugin 而且在公共 chunk 中有提取的 chunk(來自ExtractTextPlugin.extract)時 // 這個選項須要設置爲true allChunks: false, }), // duplicated CSS from different components can be deduped. // 使用這個插件壓縮css,主要是由於,對於不一樣組件中相同的css能夠剔除一部分 new OptimizeCSSPlugin({ // 這個選項的全部配置都會傳遞給cssProcessor // cssProcessor使用這些選項決定壓縮的行爲 cssProcessorOptions: config.build.productionSourceMap // safe我不是很明白是什麼意思???求留言告知。。。 ? { safe: true, map: { inline: false } } : { safe: true } }), // 建立一個html文件 new HtmlWebpackPlugin({ // 生成的文件的名稱 filename: config.build.index, // 使用的模板的名稱 template: 'index.html', // 把script和link標籤放在body底部 inject: true, // 配置html的壓縮行爲 minify: { // 移除註釋 removeComments: true, // 去除空格和換行 collapseWhitespace: true, // 儘量移除屬性中的引號和空屬性 removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, // 控制chunks的順序,這裏表示按照依賴關係進行排序 // 也能夠是一個函數,本身定義排序規則 chunksSortMode: 'dependency' }), // keep module.id stable when vender modules does not change // 根據模塊的相對路徑生成一個四位數的hash做爲模塊id new webpack.HashedModuleIdsPlugin(), // webpack2處理過的每個模塊都會使用一個函數進行包裹 // 這樣會帶來一個問題:下降瀏覽器中JS執行效率,這主要是閉包函數下降了JS引擎解析速度。 // webpack3中,經過下面這個插件就可以將一些有聯繫的模塊, // 放到一個閉包函數裏面去,經過減小閉包函數數量從而加快JS的執行速度。 new webpack.optimize.ModuleConcatenationPlugin(), // 這個插件用於提取多入口chunk的公共模塊 // 經過將公共模塊提取出來以後,最終合成的文件可以在最開始的時候加載一次 // 而後緩存起來供後續使用,這會帶來速度上的提高。 new webpack.optimize.CommonsChunkPlugin({ // 這是 common chunk 的名稱 name: 'vendor', // 把全部從mnode_modules中引入的文件提取到vendor中 minChunks (module) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) } }), // 爲了將項目中的第三方依賴代碼抽離出來,官方文檔上推薦使用這個插件,當咱們在項目裏實際使用以後, // 發現一旦更改了 app.js 內的代碼,vendor.js 的 hash 也會改變,那麼下次上線時, // 用戶仍然須要從新下載 vendor.js 與 app.js——這樣就失去了緩存的意義了。因此第二次new就是解決這個問題的 // 參考:https://github.com/DDFE/DDFE-blog/issues/10 new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', minChunks: Infinity }), new webpack.optimize.CommonsChunkPlugin({ name: 'app', async: 'vendor-async', children: true, minChunks: 3 }), // copy custom static assets // 拷貝靜態資源到build文件夾中 new CopyWebpackPlugin([ { // 定義要拷貝的資源的源目錄 from: path.resolve(__dirname, '../static'), // 定義要拷貝的資源的目標目錄 to: config.build.assetsSubDirectory, // 忽略拷貝指定的文件,可使用模糊匹配 ignore: ['.*'] } ]) ] }) if (config.build.productionGzip) { // 若是開啓了生產環境的gzip const CompressionWebpackPlugin = require('compression-webpack-plugin') webpackConfig.plugins.push( new CompressionWebpackPlugin({ // 目標資源的名稱 // [path]會被替換成原資源路徑 // [query]會被替換成原查詢字符串 asset: '[path].gz[query]', // gzip算法 // 這個選項能夠配置成zlib模塊中的各個算法 // 也能夠是(buffer, cb) => cb(buffer) algorithm: 'gzip', // 處理全部匹配此正則表達式的資源 test: new RegExp( '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), // 只處理比這個值大的資源 threshold: 10240, // 只有壓縮率比這個值小的資源纔會被處理 minRatio: 0.8 }) ) } if (config.build.bundleAnalyzerReport) { // 若是須要生成一分bundle報告,則須要使用下面的這個插件 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) } module.exports = webpackConfig
build/check-versions.js
:檢查npm和node的版本'use strict' // 在終端爲不一樣字體顯示不一樣的風格 const chalk = require('chalk') // 解析npm包的version const semver = require('semver') // 引入package.json文件 const packageConfig = require('../package.json') // node版本的uninx shell命令 const shell = require('shelljs') // 執行命令的函數 function exec (cmd) { return require('child_process').execSync(cmd).toString().trim() } const versionRequirements = [ { name: 'node', // node的版本 // process.version就是node的版本 // semver.clean('v8.8.0') => 8.8.0 currentVersion: semver.clean(process.version), // package.json中定義的node版本的範圍 versionRequirement: packageConfig.engines.node } ] // 至關於 which npm if (shell.which('npm')) { // 若是npm命令存在的話 versionRequirements.push({ name: 'npm', // 檢查npm的版本 => 5.4.2 currentVersion: exec('npm --version'), // package.json中定義的npm版本 versionRequirement: packageConfig.engines.npm }) } module.exports = function () { const warnings = [] for (let i = 0; i < versionRequirements.length; i++) { const mod = versionRequirements[i] // semver.satisfies()進行版本之間的比較 if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { // 若是現有的npm或者node的版本比定義的版本低,則生成一段警告 warnings.push(mod.name + ': ' + chalk.red(mod.currentVersion) + ' should be ' + chalk.green(mod.versionRequirement) ) } } 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) } }
build/build.js
: build項目'use strict' // 檢查npm和node的版本 require('./check-versions')() // 設置環境變量NODE_ENV的值是production process.env.NODE_ENV = 'production' // 終端的spinner const ora = require('ora') // node.js版本的rm -rf const rm = require('rimraf') // 引入path模塊 const path = require('path') // 引入顯示終端顏色模塊 const chalk = require('chalk') // 引入webpack模塊 const webpack = require('webpack') // 引入基本的配置文件 const config = require('../config') // 引入webpack在production環境下的配置文件 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 // 進行打包 webpack(webpackConfig, (err, stats) => { // 打包完成 spinner.stop() if (err) throw err // 輸出打包的狀態 process.stdout.write(stats.toString({ colors: true, modules: false, children: false, chunks: false, chunkModules: false }) + '\n\n') // 若是打包出現錯誤 if (stats.hasErrors()) { console.log(chalk.red(' Build failed with errors.\n')) process.exit(1) } // 打包完成 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' )) }) })
看着不錯,就轉過來了。html5
轉載自:https://segmentfault.com/a/1190000012472099java