1. 概述
1.1 說明
使用vue-cli快速創建的vue項目目錄如下:
1.2 build
1.3 config
config文件夾下的文件目錄如下:
1.4 .editorconfig
代碼規范化編輯可以幫助我們簡單整潔的展示代碼結構,而.editorconfig文件就是對代碼規范設置的一個文檔。使用編輯器/IDE打開項目時編輯器會自動尋找.editorconfig文件,然后根據其內容配置去顯示相關的項目代碼文件。
2. 項目頁面開發
2.1 index.html
項目頁面入口(可刪除),通常是進行根節點功能設置,如需要引用靜態資源文件夾static中的文件時,建議在index.html中進行引入;手機端文件在此文件中更改viewport等。
2.2 App.vue
app.vue時項目的主組件,所有頁面都是在app.vue下切換的(基於此組件,若多頁面的則不是)。其中<router-view/>是子路由視圖。
2.3 main.js
main.js是入口文件,主要作用是初始化vue實例並使用需要的插件。使用某些插件使用Vue.use(xxx)。
2.4 router
路由配置文件,地址為src>router>index.js。可進行自定義配置,然后引入到main.js中,加入至vue實例。
2.5 store(vuex)
自己增加文件,作用為數據倉庫,對項目中公用數據進行設置存儲。
3. webpack
webpack是當下最熱門的前端資源模塊化管理工具和打包工具,可以將很多松散的模塊按照一定的規則打包成符合生產環境的前端資源,同時具有按需加載,等到實際需要的時候進行異步加載。通過loader的轉換,在項目中任何形式的資源都可以被理解為模塊,比如img,css,js等。
3.1 webpack.base.conf.js
'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) } module.exports = { context: path.resolve(__dirname, '../'), //******入口****** entry: { app: './src/main.js' }, //輸出文件,打包到哪里,配置來源於config文件夾配置 output: { //config>index.js下的build中的assetsRoot,即dist文件夾 path: config.build.assetsRoot, //導出文件的文件名 filename: '[name].js', //生產模式或開發模式下的html,js等文件內部引用的公共路徑(config>index.js下的build或dev) publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, //文件解析 resolve: { //自動解析確定的擴展名,使導入模塊時不帶擴展名(import a from a.vue,后綴名省略) extensions: ['.js', '.vue', '.json'], alias: { // 創建import 或 require的別名 'vue$': 'vue/dist/vue.esm.js', // 用@來代替src,引用路徑時使用 '@': resolve('src'), } }, //項目中不同類型的模塊處理規則 module: { rules: [ { test: /\.vue$/,//vue 文件后綴 loader: 'vue-loader',//使用vue-loader進行處理 options: vueLoaderConfig//對vue-loader做的額外選項配置 }, { test: /\.js$/,//js文件后綴 loader: 'babel-loader',// 使用babel-loader進行處理 // 必須處理包含src test的文件夾 include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,//圖片后綴 loader: 'url-loader',//使用url-loader處理 //對loader做的額外配置 options: { limit: 10000,//小於10kb的以base64進行引用 // 文件名為name ,7位hash值,擴展名 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: { // prevent webpack from injecting useless setImmediate polyfill because Vue // source contains it (although only uses it if it's native). setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' } }
3.2 開發環境相關
3.2.1 webpack.dev.conf.js
module: { // 通過傳入一些配置來獲取rules配置,此處都為true,表示都生成 rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) }
3.2.2 styleLoaders/cssLoader(until.js)
styleLoader配置:
exports.styleLoaders = function (options) { const output = [];//返回數組,數組中保存的是針對各種類型的樣式文件的處理方式 // 調用cssLoaders方法返回各類型的樣式對象(css:loader) const loaders = exports.cssLoaders(options); // 遍歷loaders for (const extension in loaders) { //根據遍歷獲得的key(extension) 來得到value (loader) const loader = loaders[extension] output.push({ test: new RegExp('\\.' + extension + '$'),//處理文件的類型 use: loader// 用loader來處理,loader來自loaders【extension】 }) } return output }
exports.cssLoaders = function (options) { options = options || {} const cssLoader = { loader: 'css-loader', // options 是 css-loader的選項配置 options: { sourceMap: options.sourceMap// 根據參數是否要生成sourceMap文件 } } const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: options.sourceMap } } // generate loader string to be used with extract text plugin 生成loader function generateLoaders (loader, loaderOptions) { // 默認的loader是css-loader const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] if (loader) { loaders.push({ loader: loader + '-loader', // 將loaderOptions和sourceMap組成一個對象 options: Object.assign({}, loaderOptions, { sourceMap: options.sourceMap }) }) } // Extract CSS when that option is specified // (which is the case during production build) if (options.extract) { // ExtractTextPlugin 分離js中引入的css文件 return ExtractTextPlugin.extract({ use: loaders,// 處理loader fallback: 'vue-style-loader'// 沒有被提取分離時使用的loader }) } else { return ['vue-style-loader'].concat(loaders) } } // https://vue-loader.vuejs.org/en/configurations/extract-css.html //返回css類型對應的loader組成的對象 generateLoaders()來生成loader return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders('less'), sass: generateLoaders('sass', { indentedSyntax: true }), scss: generateLoaders('sass'), stylus: generateLoaders('stylus'), styl: generateLoaders('stylus') } }
webpack.dev.conf.js下的plugins。
plugins: [ //定義全局變量 new webpack.DefinePlugin({ 'process.env': require('../config/dev.env') }), // 熱更新插件 new webpack.HotModuleReplacementPlugin(), //在熱加載時直接返回更新文件名,而不是文件的id。 new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. // 不觸發錯誤,即編譯后運行的包正常運行 new webpack.NoEmitOnErrorsPlugin(), // https://github.com/ampedandwired/html-webpack-plugin // 自動生成html文件,比如編譯后文件的引用 new HtmlWebpackPlugin({ filename: 'index.html',// 生成的文件名 template: 'index.html',// 模板 inject: true }), // copy custom static assets //將資源進行復制的插件 new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.dev.assetsSubDirectory, ignore: ['.*'] } ]) ]
3.3.1 webpack.prod.conf.js
生產環境下的webpack配置,通過merge方法合並webpack.base.conf.js基礎配置。
const merge = require('webpack-merge') const baseWebpackConfig = require('./webpack.base.conf') const webpackConfig = merge(baseWebpackConfig, { module: { }, devtool: false, output: {}, plugins: [] })
3.3.2 webpack.prod.conf.js——module
module主要是針對css的處理,調用了utils.styleLoaders
module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true }) }
3.3.3 webpack.prod.conf.js——output
輸出文件的文件目錄/文件名等的設置
output: { path: config.build.assetsRoot,//導出文件目錄 filename: utils.assetsPath('js/[name].[chunkhash].js'), //導出的文件名 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')//非入口文件的文件名,而又需要被打包出來的文件命名配置,如按需加載的模塊 }
3.3.4 webpack.prod.conf.js——plugins(插件)
plugins: [ // http://vuejs.github.io/vue-loader/en/workflow/production.html new webpack.DefinePlugin({ 'process.env': env// 配置全局環境為生產環境 }), // js壓縮插件 new UglifyJsPlugin({ uglifyOptions: { // 壓縮配置 compress: { warnings: false//不顯示警告 } }, sourceMap: config.build.productionSourceMap,// 是否生成sourceMap文件 parallel: true }), // extract css into its own file 將js中引入css分離插件 new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'),// 分離出來的css文件名 allChunks: true, }), // 壓縮提取出的css,並解決ExtractTextPlugin分離出的js重復問題(多個文件引用同一個css文件) new OptimizeCSSPlugin({ cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: { inline: false } } : { safe: true } }), //生成html的插件,引入css文件和js文件 new HtmlWebpackPlugin({ filename: config.build.index,// 生成的html的文件名 template: 'index.html',// 依據的模板 inject: true,// 注入的js文件會被放在Body標簽中,當值為'head'的時候,將被放在head標簽中 // 壓縮配置 minify: { removeComments: true,// 刪除html中的注釋代碼 collapseWhitespace: true,// 刪除html中的空白符 removeAttributeQuotes: true// 刪除html元素中屬性的引號 // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin chunksSortMode: 'dependency'//按dependency的順序引入 }), // keep module.id stable when vendor modules does not change new webpack.HashedModuleIdsPlugin(), // enable scope hoisting new webpack.optimize.ModuleConcatenationPlugin(), // 分離公共js到vendor中 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 ) } }), //將運行時代碼提取到單獨的manifest文件中,防止影響vendor.js new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', minChunks: Infinity }), // This instance extracts shared chunks from code splitted chunks and bundles them // in a separate chunk, similar to the vendor chunk // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk new webpack.optimize.CommonsChunkPlugin({ name: 'app', async: 'vendor-async', children: true, minChunks: 3 }), // 復制靜態資源,將static文件內的內容復制到指定文件夾 new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory, ignore: ['.*']//忽視.*文件 } ]) ]
3.3.5 webpack.prod.conf.js——額外配置
// 配置文件開啟gzip壓縮 if (config.build.productionGzip) { // 引入壓縮文件的組件,該插件會對生成的文件進行壓縮,生成一個.gz文件 const CompressionWebpackPlugin = require('compression-webpack-plugin') webpackConfig.plugins.push( new CompressionWebpackPlugin({ asset: '[path].gz[query]',//目標文件名 algorithm: 'gzip',//使用gzip壓縮 // 滿足正則表達式的文件會被壓縮 test: new RegExp( '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), threshold: 10240,//資源文件大於10kb的時候會被壓縮 minRatio: 0.8//最小壓縮比達到0.8的時候會被壓縮 }) ) } //打包體積優化 if (config.build.bundleAnalyzerReport) { const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) }