摘要:神一樣的存在。所以呢,就利用兩天時間,參考了一些他人的文章,查閱了一些官方的配置,就在此先稍微記錄一下。這份配置解析是基于最新版本的。不過,我非常建議,先別看我的文章,自己一句一句的通讀一遍。和中的配置含義相似。
webpack--神一樣的存在。無論寫了多少次,再次相見,仍是初見。有的時候開發(fā)vue項目,對尤大的vue-cli感激涕零。但是,但是,但是。。。不是自己的東西,真的很不想折騰。所以,我們就得深入內(nèi)部,cp them us。所以呢,就利用兩天時間,參考了一些他人的文章,查閱了一些官方的配置,就在此先稍微記錄一下。
這份配置解析是基于最新版本的vue webpack template。不過,我非常建議,先別看我的文章,自己一句一句的通讀一遍。然后再來瞅瞅,畢竟,碰撞的思維才能創(chuàng)造新的發(fā)現(xiàn)。
vue webpack的配置文件還是挺多的,下面是關(guān)于此配置的基本目錄結(jié)構(gòu):
config ├── dev.env.js //dev環(huán)境變量配置 ├── index.js // dev和prod環(huán)境的一些基本配置 └── prod.env.js // prod環(huán)境變量配置 build ├── build.js // npm run build所執(zhí)行的腳本 ├── 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環(huán)境的配置 └── webpack.prod.conf.js // prod環(huán)境的配置
下面我們就按照如下的順序分析源碼:
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
config/index.js: 一些基本屬性的配置(我們可以根據(jù)自己的需要來更改這些配置)"use strict" // 這個文件主要是對開發(fā)環(huán)境和生產(chǎn)環(huán)境的一個基本的配置 const path = require("path") module.exports = { // 開發(fā)環(huán)境的一個基本配置 dev: { // 編譯輸出的二級目錄 assetsSubDirectory: "static", // 編譯發(fā)布的根目錄,可配置為資源服務(wù)器域名或者cdn域名 assetsPublicPath: "/", // 需要使用proxyTable代理的接口(可以跨域) proxyTable: {}, // 開發(fā)時候的訪問域名。可以通過環(huán)境變量自己設(shè)置。 host: "localhost", // can be overwritten by process.env.HOST // 開發(fā)時候的端口。可以通過環(huán)境變量PORT設(shè)定。如果端口被占用了,會隨機(jī)分配一個未被使用的端口 port: 8080, // 是否自動打開瀏覽器 autoOpenBrowser: false, // 下面兩個都是瀏覽器展示錯誤的方式 // 在瀏覽器是否展示錯誤蒙層 errorOverlay: true, // 是否展示錯誤的通知 notifyOnErrors: true, // 這個是webpack-dev-servr的watchOptions的一個選項,指定webpack檢查文件的方式 // 因為webpack使用文件系統(tǒng)去獲取文件改變的通知。在有些情況下,這個可能不起作用。例如,當(dāng)使用NFC的時候, // vagrant也會在這方面存在很多問題,在這些情況下,使用poll選項(以輪詢的方式去檢查文件是否改變)可以設(shè)定為true // 或者具體的數(shù)值,指定文件查詢的具體周期。 poll: false, // 是否使用eslint loader去檢查代碼 useEslint: true, // 如果設(shè)置為true,在瀏覽器中,eslint的錯誤和警告會以蒙層的方式展現(xiàn)。 showEslintErrorsInOverlay: false, /** * Source Maps */ // source maps的格式 devtool: "eval-source-map", // 指定是否通過在文件名稱后面添加一個查詢字符串來創(chuàng)建source map的緩存 cacheBusting: true, // 關(guān)閉css的source map cssSourceMap: false, }, build: { // html文件的生成的地方 index: path.resolve(__dirname, "../dist/index.html"), // 編譯生成的文件的目錄 assetsRoot: path.resolve(__dirname, "../dist"), // 編譯生成的靜態(tài)文件的目錄 assetsSubDirectory: "static", // 編譯發(fā)布的根目錄,可配置為資源服務(wù)器域名或者cdn域名 assetsPublicPath: "/", /** * Source Maps */ productionSourceMap: true, devtool: "#source-map", // 是否開啟生產(chǎn)環(huán)境的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模塊跨平臺的實現(xiàn)(不同平臺的路徑表示是不一樣的) return path.posix.join(assetsSubDirectory, _path) } // 為不同的css預(yù)處理器提供一個統(tǒng)一的生成方式,也就是統(tǒng)一處理各種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 } } // 創(chuàng)建loader加載器字符串,結(jié)合extract text插件使用 /** * * @param {loader的名稱} loader * @param {loader對應(yīng)的options配置對象} loaderOptions */ function generateLoaders (loader, loaderOptions) { // 通過usePostCSS 來標(biāo)明是否使用了postcss const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] // 如果指定了具體的loader的名稱 if (loader) { // 向loaders的數(shù)組中添加該loader對應(yīng)的加載器 // 一個很重要的地方就是,一個數(shù)組中的loader加載器,是從右向左執(zhí)行的。 loaders.push({ // loader加載器的名稱 loader: loader + "-loader", // 對應(yīng)的加載器的配置對象 options: Object.assign({}, loaderOptions, { sourceMap: options.sourceMap }) }) } // 如果明確指定了需要提取靜態(tài)文件,則使用 // ExtractTextPlugin.extract({})來包裹我們的各種css處理器。 if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, // fallback這個選項我們可以這樣理解 // webpack默認(rèn)會按照loaders中的加載器從右向左調(diào)用編譯各種css類型文件。如果一切順利,在loaders中的 // 各個加載器運行結(jié)束之后就會把css文件導(dǎo)入到規(guī)定的文件中去,如果不順利,則繼續(xù)使用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使用的是縮進(jìn)的愈發(fā) sass: generateLoaders("sass", { indentedSyntax: true }), // scss-loader scss: generateLoaders("sass"), // stylus-loader stylus文件有兩種后綴名.stylus和styl stylus: generateLoaders("stylus"), // stylus-loader styl: generateLoaders("stylus") } } // 使用這個函數(shù),為那些獨立的style文件創(chuàng)建加載器配置。 exports.styleLoaders = function (options) { // 保存加載器配置的變量 const output = [] // 獲取所有css文件類型的loaders const loaders = exports.cssLoaders(options) for (const extension in loaders) { const loader = loaders[extension] // 生成對應(yīng)的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() // 需要展示的錯誤信息的內(nèi)容 notifier.notify({ // 通知的標(biāo)題 title: packageConfig.name, // 通知的主體內(nèi)容 message: severity + ": " + error.name, // 副標(biāo)題 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") // 設(shè)置是不是生產(chǎn)環(huán)境 const isProduction = process.env.NODE_ENV === "production" // 根據(jù)不同的環(huán)境,引入不同的source map配置文件 const sourceMapEnabled = isProduction ? config.build.productionSourceMap : config.dev.cssSourceMap module.exports = { // vue文件中的css loader配置 loaders: utils.cssLoaders({ sourceMap: sourceMapEnabled, // 生產(chǎn)環(huán)境下就會把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環(huán)境下的公共配置
"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的規(guī)則 const createLintingRule = () => ({ // 對.js和.vue結(jié)尾的文件進(jìn)行eslint檢查 test: /.(js|vue)$/, // 使用eslint-loader loader: "eslint-loader", // enforce的值可能是pre和post。其中pre有點和webpack@1中的preLoader配置含義相似。 // post和v1中的postLoader配置含義相似。表示loader的調(diào)用時機(jī) // 這里表示在調(diào)用其他loader之前需要先調(diào)用這個規(guī)則進(jìn)行代碼風(fēng)格的檢查 enforce: "pre", // 需要進(jìn)行eslint檢查的文件的目錄存在的地方 include: [resolve("src"), resolve("test")], // eslint-loader配置過程中需要指定的選項 options: { // 文件風(fēng)格的檢查的格式化程序,這里使用的是第三方的eslint-friendly-formatter formatter: require("eslint-friendly-formatter"), // 是否需要eslint輸出警告信息 emitWarning: !config.dev.showEslintErrorsInOverlay } }) // 下面就是webpack基本的配置信息(可以立即成是開發(fā)環(huán)境和生產(chǎn)環(huán)境公共的配置) 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等靜態(tài)文件的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"), } }, // 下面是針對具體的模塊進(jìn)行的具體的配置 // 下面的配置語法采用的是version >= @2的版本 module: { // rules是一個數(shù)組,其中的每一個元素都是一個對象,這個對象是針對具體類型的文件進(jìn)行的配置。 rules: [ // .vue文件的配置 { // 這個屬性是一個正則表達(dá)式,用于匹配文件。這里匹配的是.vue文件 test: /.vue$/, // 指定該種類型文件的加載器名稱 loader: "vue-loader", // 針對此加載器的具體配置 // 針對前面的分析,這個配置對象中包含了各種css類型文件的配置,css source map的配置 以及一些transform的配置 options: vueLoaderConfig }, { // .js文件的配置 test: /.js$/, // js文件的處理主要使用的是babel-loader。在這里沒有指定具體的編譯規(guī)則,babel-loader會自動 // 讀取根目錄下面的.babelrc中的babel配置用于編譯js文件 /** * { * // 使用的預(yù)設(shè) "presets": [ // babel-preset-env: 根據(jù)你所支持的環(huán)境自動決定具體類型的babel插件 ["env", { // modules設(shè)置為false,不會轉(zhuǎn)換module "modules": false }], // babel-preset-stage-2: 可以使用所有>=stage2語法 "stage-2" ], // 使用的插件 // babel-plugin-transform-runtime: 只會對es6的語法進(jìn)行轉(zhuǎn)換而不會對新的api進(jìn)行轉(zhuǎn)換 // 如果需要支持新的api,請引入babel-polyfill "plugins": ["transform-runtime"] } */ loader: "babel-loader", // 指定需要進(jìn)行編譯的文件的路徑 // 這里表示只對src和test文件夾中的文件進(jìn)行編譯 include: [resolve("src"), resolve("test")] }, { // 對圖片資源進(jìn)行編譯的配置 // 指定文件的類型 test: /.(png|jpe?g|gif|svg)(?.*)?$/, // 使用url-loader進(jìn)行文件資源的編譯 loader: "url-loader", // url-loader的配置選項 options: { // 文件的大小小于10000字節(jié)(10kb)的時候會返回一個dataUrl limit: 10000, // 生成的文件的保存路徑和后綴名稱 name: utils.assetsPath("img/[name].[hash:7].[ext]") } }, { // 對視頻文件進(jìn)行打包編譯 test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/, loader: "url-loader", options: { limit: 10000, name: utils.assetsPath("media/[name].[hash:7].[ext]") } }, { // 對字體文件進(jìn)行打包編譯 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表示什么都不提供。如果獲取此對象的代碼,可能會因為獲取不到此對象而觸發(fā)ReferenceError錯誤 setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client // 設(shè)置成empty則表示提供一個空對象 dgram: "empty", fs: "empty", net: "empty", tls: "empty", child_process: "empty" } }build/weboack.dev.conf.js:dev環(huán)境的配置
"use strict" // 首先引入的是一些工具方法,下面我們就需要去util文件種看一下有哪些對應(yīng)的工具方法 const utils = require("./utils") // 引入webpack模塊 const webpack = require("webpack") // 引入配置文件 // 這個配置文件中包含了一些dev和production環(huán)境的基本配置 const config = require("../config") // 引入webpack-merge模塊。這個模塊用于把多個webpack配置合并成一個配置,后面的配置會覆蓋前面的配置。 const merge = require("webpack-merge") // 引入webpack的基本設(shè)置,這個設(shè)置文件包含了開發(fā)環(huán)境和生產(chǎn)環(huán)境的一些公共配置 const baseWebpackConfig = require("./webpack.base.conf") // 用于生成html文件的插件 const HtmlWebpackPlugin = require("html-webpack-plugin") // 這個插件能夠更好的在終端看到webpack運行時的錯誤和警告等信息。可以提升開發(fā)體驗。 const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin") // 查找一個未使用的端口 const portfinder = require("portfinder") // 獲取host環(huán)境變量,用于配置開發(fā)環(huán)境域名 const HOST = process.env.HOST // 獲取post環(huán)境變量,用于配置開發(fā)環(huán)境時候的端口號 const PORT = process.env.PORT && Number(process.env.PORT) // 開發(fā)環(huán)境的完整的配置文件, const devWebpackConfig = merge(baseWebpackConfig, { module: { // 為那些獨立的css類型文件添加loader配置(沒有寫在vue文件的style標(biāo)簽中的樣式) rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) }, // 開發(fā)環(huán)境使用"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 // 文件中進(jìn)行自定義配置。 devServer: { // 用于配置在開發(fā)工具的控制臺中顯示的日志級別 // 注意這個不是對bundle的錯誤和警告的配置,而是對它生成之前的消息的配置 clientLogLevel: "warning", // 表示當(dāng)使用html5的history api的時候,任意的404響應(yīng)都需要被替代為index.html historyApiFallback: true, // 啟用webpack的熱替換特性 hot: true, // 一切服務(wù)都需要使用gzip壓縮 // 可以在js,css等文件的response header中發(fā)現(xiàn)有Content-Encoding:gzip響應(yīng)頭 compress: true, // 指定使用一個 host。默認(rèn)是 localhost // 如果希望服務(wù)器外部可以訪問(通過我們電腦的ip地址和端口號訪問我們的應(yīng)用) // 可以指定0.0.0.0 host: HOST || config.dev.host, // 指定要監(jiān)聽請求的端口號 port: PORT || config.dev.port, // 是否自動打開瀏覽器 open: config.dev.autoOpenBrowser, // 當(dāng)編譯出現(xiàn)錯誤的時候,是否希望在瀏覽器中展示一個全屏的蒙層來展示錯誤信息 overlay: config.dev.errorOverlay // 表示只顯示錯誤信息而不顯示警告信息 // 如果兩者都希望顯示,則把這兩項都設(shè)置為true ? { warnings: false, errors: true } // 設(shè)置為false則表示啥都不顯示 : false, // 指定webpack-dev-server的根目錄,這個目錄下的所有的文件都是能直接通過瀏覽器訪問的 // 推薦和output.publicPath設(shè)置為一致 publicPath: config.dev.assetsPublicPath, // 配置代理,這樣我們就可以跨域訪問某些接口 // 我們訪問的接口,如果符合這個選項的配置,就會通過代理服務(wù)器轉(zhuǎn)發(fā)我們的請求 proxy: config.dev.proxyTable, // 啟用 quiet 后,除了初始啟動信息之外的任何內(nèi)容都不會被打印到控制臺。這也意味著來自 webpack 的錯誤或警告在控制臺不可見。 quiet: true, // necessary for FriendlyErrorsPlugin // 與監(jiān)視文件相關(guān)的控制選項。 watchOptions: { // 如果這個選項為true,會以輪詢的方式檢查我們的文件的變動,效率不好 poll: config.dev.poll, } }, plugins: [ // 創(chuàng)建一個在編譯時可以配置的全局變量 new webpack.DefinePlugin({ "process.env": require("../config/dev.env") }), // 啟用熱替換模塊 // 記住,我們永遠(yuǎn)不要再生產(chǎn)環(huán)境中使用hmr new webpack.HotModuleReplacementPlugin(), // 這個插件的主要作用就是在熱加載的時候直接返回更新文件的名稱,而不是文件的id new webpack.NamedModulesPlugin(), // 使用這個插件可以在編譯出錯的時候來跳過輸出階段,這樣可以確保輸出資源不會包含錯誤。 new webpack.NoEmitOnErrorsPlugin(), // 這個插件主要是生成一個html文件 new HtmlWebpackPlugin({ // 生成的html文件的名稱 filename: "index.html", // 使用的模板的名稱 template: "index.html", // 將所有的靜態(tài)文件都插入到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 { // 把獲取到的端口號設(shè)置為環(huán)境變量PORT的值 process.env.PORT = port // 重新設(shè)置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}`], }, // 當(dāng)編譯出錯的時候,根據(jù)config.dev.notifyOnErrors來確定是否需要在桌面右上角顯示錯誤通知框 onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined })) // resolve我們的配置文件 resolve(devWebpackConfig) } }) })build/webpack.prod.conf.js:prod環(huán)境的基本配置
"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") // 引入開發(fā)環(huán)境和生產(chǎn)環(huán)境公共的配置 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") // 引入用于生產(chǎn)環(huán)境的一些基本變量 const env = require("../config/prod.env") // 合并公共配置和生產(chǎn)環(huán)境獨有的配置并返回一個用于生產(chǎn)環(huán)境的webpack配置文件 const webpackConfig = merge(baseWebpackConfig, { // 用于生產(chǎn)環(huán)境的一些loader配置 module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, // 在生產(chǎn)環(huán)境中使用extract選項,這樣就會把thunk中的css代碼抽離到一份獨立的css文件中去 extract: true, usePostCSS: true }) }, // 配置生產(chǎn)環(huán)境中使用的source map的形式。在這里,生產(chǎn)環(huán)境使用的是#source map的形式 devtool: config.build.productionSourceMap ? config.build.devtool : false, output: { // build所產(chǎn)生的文件的存放的文件夾地址 path: config.build.assetsRoot, // build之后的文件的名稱 // 這里[name]和[chunkhash]都是占位符 // 其中[name]指的就是模塊的名稱 // [chunkhash]chunk內(nèi)容的hash字符串,長度為20 filename: utils.assetsPath("js/[name].[chunkhash].js"), // [id]也是一個占位符,表示的是模塊標(biāo)識符(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: { // 在刪除未使用的變量等時,顯示警告信息,默認(rèn)就是false warnings: false } }, // 使用 source map 將錯誤信息的位置映射到模塊(這會減慢編譯的速度) // 而且這里不能使用cheap-source-map sourceMap: config.build.productionSourceMap, // 使用多進(jìn)程并行運行和文件緩存來提高構(gòu)建速度 parallel: true }), // 提取css文件到一個獨立的文件中去 new ExtractTextPlugin({ // 提取之后css文件存放的地方 // 其中[name]和[contenthash]都是占位符 // [name]就是指模塊的名稱 // [contenthash]根據(jù)提取文件的內(nèi)容生成的 hash filename: utils.assetsPath("css/[name].[contenthash].css"), // 從所有額外的 chunk(additional chunk) 提取css內(nèi)容 // (默認(rèn)情況下,它僅從初始chunk(initial chunk) 中提取) // 當(dāng)使用 CommonsChunkPlugin 并且在公共 chunk 中有提取的 chunk(來自ExtractTextPlugin.extract)時 // 這個選項需要設(shè)置為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 } }), // 創(chuàng)建一個html文件 new HtmlWebpackPlugin({ // 生成的文件的名稱 filename: config.build.index, // 使用的模板的名稱 template: "index.html", // 把script和link標(biāo)簽放在body底部 inject: true, // 配置html的壓縮行為 minify: { // 移除注釋 removeComments: true, // 去除空格和換行 collapseWhitespace: true, // 盡可能移除屬性中的引號和空屬性 removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, // 控制chunks的順序,這里表示按照依賴關(guān)系進(jìn)行排序 // 也可以是一個函數(shù),自己定義排序規(guī)則 chunksSortMode: "dependency" }), // keep module.id stable when vender modules does not change // 根據(jù)模塊的相對路徑生成一個四位數(shù)的hash作為模塊id new webpack.HashedModuleIdsPlugin(), // webpack2處理過的每一個模塊都會使用一個函數(shù)進(jìn)行包裹 // 這樣會帶來一個問題:降低瀏覽器中JS執(zhí)行效率,這主要是閉包函數(shù)降低了JS引擎解析速度。 // webpack3中,通過下面這個插件就能夠?qū)⒁恍┯新?lián)系的模塊, // 放到一個閉包函數(shù)里面去,通過減少閉包函數(shù)數(shù)量從而加快JS的執(zhí)行速度。 new webpack.optimize.ModuleConcatenationPlugin(), // 這個插件用于提取多入口chunk的公共模塊 // 通過將公共模塊提取出來之后,最終合成的文件能夠在最開始的時候加載一次 // 然后緩存起來供后續(xù)使用,這會帶來速度上的提升。 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 ) } }), // 為了將項目中的第三方依賴代碼抽離出來,官方文檔上推薦使用這個插件,當(dāng)我們在項目里實際使用之后, // 發(fā)現(xiàn)一旦更改了 app.js 內(nèi)的代碼,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 // 拷貝靜態(tài)資源到build文件夾中 new CopyWebpackPlugin([ { // 定義要拷貝的資源的源目錄 from: path.resolve(__dirname, "../static"), // 定義要拷貝的資源的目標(biāo)目錄 to: config.build.assetsSubDirectory, // 忽略拷貝指定的文件,可以使用模糊匹配 ignore: [".*"] } ]) ] }) if (config.build.productionGzip) { // 如果開啟了生產(chǎn)環(huán)境的gzip const CompressionWebpackPlugin = require("compression-webpack-plugin") webpackConfig.plugins.push( new CompressionWebpackPlugin({ // 目標(biāo)資源的名稱 // [path]會被替換成原資源路徑 // [query]會被替換成原查詢字符串 asset: "[path].gz[query]", // gzip算法 // 這個選項可以配置成zlib模塊中的各個算法 // 也可以是(buffer, cb) => cb(buffer) algorithm: "gzip", // 處理所有匹配此正則表達(dá)式的資源 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 = webpackConfigbuild/check-versions.js:檢查npm和node的版本
"use strict" // 在終端為不同字體顯示不同的風(fēng)格 const chalk = require("chalk") // 解析npm包的version const semver = require("semver") // 引入package.json文件 const packageConfig = require("../package.json") // node版本的uninx shell命令 const shell = require("shelljs") // 執(zhí)行命令的函數(shù) 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 } ] // 相當(dāng)于 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()進(jìn)行版本之間的比較 if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { // 如果現(xiàn)有的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")() // 設(shè)置環(huán)境變量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環(huán)境下的配置文件 const webpackConfig = require("./webpack.prod.conf") // const spinner = ora("building for production...") spinner.start() // 刪除打包目標(biāo)目錄下的文件 rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { if (err) throw err // 進(jìn)行打包 webpack(webpackConfig, (err, stats) => { // 打包完成 spinner.stop() if (err) throw err // 輸出打包的狀態(tài) process.stdout.write(stats.toString({ colors: true, modules: false, children: false, chunks: false, chunkModules: false }) + " ") // 如果打包出現(xiàn)錯誤 if (stats.hasErrors()) { console.log(chalk.red(" Build failed with errors. ")) process.exit(1) } // 打包完成 console.log(chalk.cyan(" Build complete. ")) console.log(chalk.yellow( " Tip: built files are meant to be served over an HTTP server. " + " Opening index.html over file:// won"t work. " )) }) })
拍磚,bingo?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/92223.html
摘要:借助,我們通過非常簡單的問答形式,方便地初始化一個工程,完全不需要擔(dān)心繁復(fù)的配置等等。簡單來說,就是不僅僅能初始化工程,理論上能夠初始化一切工程,包括,等等等等,只要你有一份能夠運行的模板,就能夠通過進(jìn)行工程的初始化。 相信對于大部分使用過VueJS的同學(xué)來說,vue-cli是他們非常熟悉的一個工具。借助vue-cli,我們通過非常簡單的問答形式,方便地初始化一個vue工程,完全不需要...
摘要:自定義自己的模板在使用的過程中,常用的模板只為我們提供最基礎(chǔ)的內(nèi)容,但每次需要新建一個項目的時候就需要把之前項目的一些配置都搬過來,這樣就造成挺大的不方便,如果是作為一個團(tuán)隊,那么維護(hù)一個通用的模板,我認(rèn)為是挺有必要的。 自定義自己的vue-cli模板 在使用vue-cli的過程中,常用的webpack模板只為我們提供最基礎(chǔ)的內(nèi)容,但每次需要新建一個項目的時候就需要把之前項目的一些配置...
摘要:自定義自己的模板在使用的過程中,常用的模板只為我們提供最基礎(chǔ)的內(nèi)容,但每次需要新建一個項目的時候就需要把之前項目的一些配置都搬過來,這樣就造成挺大的不方便,如果是作為一個團(tuán)隊,那么維護(hù)一個通用的模板,我認(rèn)為是挺有必要的。 自定義自己的vue-cli模板 在使用vue-cli的過程中,常用的webpack模板只為我們提供最基礎(chǔ)的內(nèi)容,但每次需要新建一個項目的時候就需要把之前項目的一些配置...
摘要:樣式通過標(biāo)簽包裹,默認(rèn)是影響全局的,如需定義作用域只在該組件下起作用,需在標(biāo)簽上加,如要引入外部文件,首先需給項目安裝依賴包,打開,進(jìn)入項目目錄,輸入回車。 showImg(https://segmentfault.com/img/remote/1460000013235090); (一)安裝node.js 首先需要安裝node環(huán)境,可以直接到中文官網(wǎng)http://nodejs.cn/...
摘要:別名相當(dāng)于前面先引入了路由插件,然后顯式聲明要用路由。注意到,等都是頁面也可以是組件,接著注冊路由器,然后開始配置路由。 搭建環(huán)境 工欲善其事必先利其器,我們的學(xué)習(xí)計劃從學(xué)會搭建Vue所需要的環(huán)境開始,node和npm的環(huán)境不用說是必須的,現(xiàn)在前端流程化很熱門,基本上新的技術(shù)都會在這套流程的基礎(chǔ)上做開發(fā),我們只需要站在巨人的XX上裝*就可以了。我假設(shè)你的機(jī)子上已經(jīng)有了最新的node和n...
閱讀 854·2023-04-26 00:11
閱讀 2655·2021-11-04 16:13
閱讀 2101·2021-09-09 09:33
閱讀 1470·2021-08-20 09:35
閱讀 3816·2021-08-09 13:42
閱讀 3603·2019-08-30 15:55
閱讀 1037·2019-08-30 15:55
閱讀 2218·2019-08-30 13:55