vue-cli 目錄結構詳細講解

https://juejin.im/post/5c3599386fb9a049db7351a8php

 

 

vue-cli 目錄結構詳細講解
目錄
結構預覽
├─build                 // 保存一些webpack的初始化配置,項目構建
│ ├─build.js            // 生產環境構建
│ ├─check-version.js    // 檢查npm、node版本
│ ├─vue-loader.conf.js  // webpack loader配置
│ ├─webpack.base.conf.js// webpack基礎配置
│ ├─webpack.dev.conf.js // 開發環境配置,構建本地開發服務器
│ ├─webpack.prod.conf.js// 生產環境的配置
│
├─config                // config文件夾保存一些項目初始化的配置
│ ├─dev.env.js          // 開發環境的配置
│ ├─index.js            // 項目一些配置變量
│ ├─prod.env.js         // 生產環境的配置
│
├─dist                  // 打包後的項目
├─node_modules          // 依賴包
│
├─src                   // 源碼目錄
│ ├─assets              // 靜態文件目錄
│ ├─components          // 組件文件
│ ├─router              // 路由
│ ├─App.vue             // 是項目入口文件
│ ├─main.js             // 是項目的核心文件,入口
├─static                // 靜態資源目錄 
├─.babelrc              // Babel的配置文件
├─.editorconfig         // 代碼規範配置文件
├─.gitignore            // git忽略配置文件
├─.postcssrc.js         // postcss插件配置文件
├─index.html            // 頁面入口文件
├─package-lock.json     // 項目包管控文件
├─package.json          // 項目配置
└─README.md             // 項目說明書
複製代碼
結構解析
build
dev-server.js
首先來看執行」npm run dev」時候最早執行的build/dev-server.js文件。該文件主要完成下面幾件事情:

檢查node和npm的版本、引入相關插件和配置
webpack對源碼進行編譯打包並返回compiler對象
建立express服務器
配置開發中間件(webpack-dev-middleware)和+ 熱重載中間件(webpack-hot-middleware)
掛載代理服務和中間件
配置靜態資源
啓動服務器監聽特定端口(8080)
自動打開瀏覽器並打開特定網址(localhost:8080)
說明: express服務器提供靜態文件服務,不過它還使用了http-proxy-middleware,一個http請求代理的中間件。前端開發過程當中須要使用到後臺的API的話,能夠經過配置proxyTable來將相應的後臺請求代理到專用的API服務器。

// 檢查NodeJS和npm的版本
require('./check-versions')()

// 獲取基本配置
var config = require('../config')
// 若是Node的環境變量中沒有設置當前的環境(NODE_ENV),則使用config中的dev環境配置做爲當前的環境
if (!process.env.NODE_ENV) {
  process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}

// opn是一個能夠調用默認軟件打開網址、圖片、文件等內容的插件
// 這裏用它來調用默認瀏覽器打開dev-server監聽的端口,例如:localhost:8080
var opn = require('opn')
var path = require('path')
var express = require('express')
var webpack = require('webpack')
// http-proxy-middleware是一個express中間件,用於將http請求代理到其餘服務器
// 例:localhost:8080/api/xxx  -->  localhost:3000/api/xxx
// 這裏使用該插件能夠將前端開發中涉及到的請求代理到提供服務的後臺服務器上,方便與服務器對接
var proxyMiddleware = require('http-proxy-middleware')
// 開發環境下的webpack配置
var webpackConfig = require('./webpack.dev.conf')

// dev-server 監聽的端口,若是沒有在命令行傳入端口號,則使用config.dev.port設置的端口,例如8080
var port = process.env.PORT || config.dev.port
// 用於判斷是否要自動打開瀏覽器的布爾變量,當配置文件中沒有設置自動打開瀏覽器的時候其值爲 false
var autoOpenBrowser = !!config.dev.autoOpenBrowser
// HTTP代理表,指定規則,將某些API請求代理到相應的服務器
var proxyTable = config.dev.proxyTable
// 建立express服務器
var app = express()
// webpack根據配置開始編譯打包源碼並返回compiler對象
var compiler = webpack(webpackConfig)
// webpack-dev-middleware將webpack編譯打包後獲得的產品文件存放在內存中而沒有寫進磁盤
// 將這個中間件掛到express上使用以後便可提供這些編譯後的產品文件服務
var devMiddleware = require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath, // 設置訪問路徑爲webpack配置中的output裏面所對應的路徑
  quiet: true // 設置爲true,使其不要在控制檯輸出日誌
})
// webpack-hot-middleware,用於實現熱重載功能的中間件
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
  log: false, // 關閉控制檯的日誌輸出
  heartbeat: 2000 // 發送心跳包的頻率
})
// webpack(從新)編譯打包完成後並將js、css等文件inject到html文件以後,經過熱重載中間件強制頁面刷新
compiler.plugin('compilation', function (compilation) {
  compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
    hotMiddleware.publish({ action: 'reload' })
    cb()
  })
})

// 根據 proxyTable 中的代理請求配置來設置express服務器的http代理規則
Object.keys(proxyTable).forEach(function (context) {
  var options = proxyTable[context]
  // 格式化options,例如將'www.example.com'變成{ target: 'www.example.com' }
  if (typeof options === 'string') {
    options = { target: options }
  }
  app.use(proxyMiddleware(options.filter || context, options))
})

// handle fallback for HTML5 history API
// 重定向不存在的URL,用於支持SPA(單頁應用)
// 例如使用vue-router並開啓了history模式
app.use(require('connect-history-api-fallback')())

// serve webpack bundle output
// 掛載webpack-dev-middleware中間件,提供webpack編譯打包後的產品文件服務
app.use(devMiddleware)

// enable hot-reload and state-preserving
// compilation error display
// 掛載熱重載中間件
app.use(hotMiddleware)

// serve pure static assets
// 提供static文件夾上的靜態文件服務
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static('./static'))

// 訪問連接
var uri = 'http://localhost:' + port

// 建立promise,在應用服務啓動以後resolve
// 便於外部文件require了這個dev-server以後的代碼編寫
var _resolve
var readyPromise = new Promise(resolve => {
  _resolve = resolve
})

console.log('> Starting dev server...')
// webpack-dev-middleware等待webpack完成全部編譯打包以後輸出提示語到控制檯,代表服務正式啓動
// 服務正式啓動才自動打開瀏覽器進入頁面
devMiddleware.waitUntilValid(() => {
  console.log('> Listening at ' + uri + '\n')
  // when env is testing, don't need open it
  if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
    opn(uri)
  }
  _resolve()
})

// 啓動express服務器並監聽相應的端口
var server = app.listen(port)

// 暴露本模塊的功能給外部使用,例以下面這種用法
// var devServer = require('./build/dev-server')
// devServer.ready.then(() => {...})
// if (...) { devServer.close() }
module.exports = {
  ready: readyPromise,
  close: () => {
    server.close()
  }
}

複製代碼
webpack.base.conf.js
從代碼中看到,dev-server使用的webpack配置來自build/webpack.dev.conf.js文件(測試環境下使用的是build/webpack.prod.conf.js,這裏暫時不考慮測試環境)。而build/webpack.dev.conf.js中又引用了webpack.base.conf.js,因此這裏我先分析webpack.base.conf.js。

webpack.base.conf.js主要完成了下面這些事情:

配置webpack編譯入口
配置webpack輸出路徑和命名規則
配置模塊resolve規則
配置不一樣類型模塊的處理規則
說明: 這個配置裏面只配置了.js、.vue、圖片、字體等幾類文件的處理規則,若是須要處理其餘文件能夠在module.rules裏面另行配置。

var path = require('path')
var fs = require('fs')
var utils = require('./utils')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')

// 獲取絕對路徑
function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  // webpack入口文件
  entry: {
    app: './src/main.js'
  },
  // webpack輸出路徑和命名規則
  output: {
    // webpack輸出的目標文件夾路徑(例如:/dist)
    path: config.build.assetsRoot,
    // webpack輸出bundle文件命名格式
    filename: '[name].js',
    // webpack編譯輸出的發佈路徑(例如'//cdn.xxx.com/app/')
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  // 模塊resolve的規則
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    // 別名,方便引用模塊,例若有了別名以後,
    // import Vue from 'vue/dist/vue.common.js'能夠寫成 import Vue from 'vue'
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
    symlinks: false
  },
  // 不一樣類型模塊的處理規則
  module: {
    rules: [
      {// 對src和test文件夾下的.js和.vue文件使用eslint-loader進行代碼規範檢查
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {// 對全部.vue文件使用vue-loader進行編譯
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {// 對src和test文件夾下的.js文件使用babel-loader將es6+的代碼轉成es5
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {// 對圖片資源文件使用url-loader
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          // 小於10K的圖片轉成base64編碼的dataURL字符串寫到代碼中
          limit: 10000,
          // 其餘的圖片轉移到靜態資源文件夾
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {// 對多媒體資源文件使用url-loader
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          // 小於10K的資源轉成base64編碼的dataURL字符串寫到代碼中
          limit: 10000,
          // 其餘的資源轉移到靜態資源文件夾
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {// 對字體資源文件使用url-loader
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          // 小於10K的資源轉成base64編碼的dataURL字符串寫到代碼中
          limit: 10000,
          // 其餘的資源轉移到靜態資源文件夾
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}

複製代碼
webpack.dev.conf.js
接下來看webpack.dev.conf.js,這裏面在webpack.base.conf的基礎上增長完善了開發環境下面的配置,主要包括下面幾件事情:

將webpack的熱重載客戶端代碼添加到每一個entry對應的應用
合併基礎的webpack配置
配置樣式文件的處理規則,styleLoaders
配置Source Maps
配置webpack插件
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
// webpack-merge是一個能夠合併數組和對象的插件
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
// html-webpack-plugin用於將webpack編譯打包後的產品文件注入到html模板中
// 即自動在index.html裏面加上<link>和<script>標籤引用webpack打包後的文件
var HtmlWebpackPlugin = require('html-webpack-plugin')
// friendly-errors-webpack-plugin用於更友好地輸出webpack的警告、錯誤等信息
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

// add hot-reload related code to entry chunks
// 給每一個入口頁面(應用)加上dev-client,用於跟dev-server的熱重載插件通訊,實現熱更新
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

module.exports = merge(baseWebpackConfig, {
  module: {
    // 樣式文件的處理規則,對css/sass/scss等不一樣內容使用相應的styleLoaders
    // 由utils配置出各類類型的預處理語言所須要使用的loader,例如sass須要使用sass-loader
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // cheap-module-eval-source-map is faster for development
  // 使用這種source-map更快
  devtool: '#cheap-module-eval-source-map',
  // webpack插件
  plugins: [
    new webpack.DefinePlugin({
      'process.env': config.dev.env
    }),
    // 開啓webpack熱更新功能
    new webpack.HotModuleReplacementPlugin(),
    // webpack編譯過程當中出錯的時候跳過報錯階段,不會阻塞編譯,在編譯結束後報錯
    new webpack.NoEmitOnErrorsPlugin(),
    // 自動將依賴注入html模板,並輸出最終的html文件到目標文件夾
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),
    new FriendlyErrorsPlugin()
  ]
})
複製代碼
utils
此配置文件是vue開發環境的wepack相關配置文件,主要用來處理css-loader和vue-style-loader

// 引入nodejs路徑模塊
var path = require('path')
// 引入config目錄下的index.js配置文件
var config = require('../config')
// 引入extract-text-webpack-plugin插件,用來將css提取到單獨的css文件中
// 詳情請看(1)
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// exports其實就是一個對象,用來導出方法的最終仍是使用module.exports,此處導出assetsPath
exports.assetsPath = function (_path) {
  // 若是是生產環境assetsSubDirectory就是'static',不然仍是'static',哈哈哈
  var assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory
  // path.join和path.posix.join的區別就是,前者返回的是完整的路徑,後者返回的是完整路徑的相對根路徑
  // 也就是說path.join的路徑是C:a/a/b/xiangmu/b,那麼path.posix.join就是b
  return path.posix.join(assetsSubDirectory, _path)
  // 因此這個方法的做用就是返回一個乾淨的相對根路徑
}
 
// 下面是導出cssLoaders的相關配置
exports.cssLoaders = function (options) {
  // options若是沒值就是空對象
  options = options || {}
  // cssLoader的基本配置
  var cssLoader = {
    loader: 'css-loader',
    options: {
      // options是用來傳遞參數給loader的
      // minimize表示壓縮,若是是生產環境就壓縮css代碼
      minimize: process.env.NODE_ENV === 'production',
      // 是否開啓cssmap,默認是false
      sourceMap: options.sourceMap
    }
  }
 
  // generate loader string to be used with extract text plugin
  function generateLoaders (loader, loaderOptions) {
    // 將上面的基礎cssLoader配置放在一個數組裏面
    var loaders = [cssLoader]
    // 若是該函數傳遞了單獨的loader就加到這個loaders數組裏面,這個loader多是less,sass之類的
    if (loader) {
      loaders.push({
        // 加載對應的loader
        loader: loader + '-loader',
        // Object.assign是es6的方法,主要用來合併對象的,淺拷貝
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }
 
    // Extract CSS when that option is specified
    // (which is the case during production build)
    // 注意這個extract是自定義的屬性,能夠定義在options裏面,主要做用就是當配置爲true就把文件單獨提取,false表示不單獨提取,這個能夠在使用的時候單獨配置,瞬間以爲vue做者好牛逼
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
    // 上面這段代碼就是用來返回最終讀取和導入loader,來處理對應類型的文件
  }
 
  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
  return {
    css: generateLoaders(), // css對應 vue-style-loader 和 css-loader
    postcss: generateLoaders(), // postcss對應 vue-style-loader 和 css-loader
    less: generateLoaders('less'), // less對應 vue-style-loader 和 less-loader
    sass: generateLoaders('sass', { indentedSyntax: true }), // sass對應 vue-style-loader 和 sass-loader
    scss: generateLoaders('sass'), // scss對應 vue-style-loader 和 sass-loader
    stylus: generateLoaders('stylus'), // stylus對應 vue-style-loader 和 stylus-loader
    styl: generateLoaders('stylus') // styl對應 vue-style-loader 和 styl-loader 
  }
}
 
// Generate loaders for standalone style files (outside of .vue)
// 下面這個主要處理import這種方式導入的文件類型的打包,上面的exports.cssLoaders是爲這一步服務的
exports.styleLoaders = function (options) {
  var output = []
  // 下面就是生成的各類css文件的loader對象
  var loaders = exports.cssLoaders(options)
  for (var extension in loaders) {
    // 把每一種文件的laoder都提取出來
    var loader = loaders[extension]
    output.push({
      // 把最終的結果都push到output數組中,大事搞定
      test: new RegExp('\\.' + extension + '$'),
      use: loader
    })
  }
  return output
}
複製代碼
extract-text-webpack-plugin插件是用來將文本從bundle中提取到一個單獨的文件中

const ExtractTextPlugin = require("extract-text-webpack-plugin");
 module.exports = {
   module: {
     rules: [
       {
         test: /\.css$/, //主要用來處理css文件
         use: ExtractTextPlugin.extract({
           fallback: "style-loader", // fallback表示若是css文件沒有成功導入就使用style-loader導入
           use: "css-loader" // 表示使用css-loader從js讀取css文件
         })
       }
     ],
     plugins: [
       new ExtractTextPlugin("styles.css") //表示生成styles.css文件
     ]
   }
 }
複製代碼
vue-loader.conf.js
var utils = require('./utils')
var config = require('../config')
var isProduction = process.env.NODE_ENV === 'production'

module.exports = {
  // 處理.vue文件中的樣式
  loaders: utils.cssLoaders({
    // 是否打開source-map
    sourceMap: isProduction
      ? config.build.productionSourceMap
      : config.dev.cssSourceMap,
    // 是否提取樣式到單獨的文件
    extract: isProduction
  }),
  transformToRequire: {
    video: 'src',
    source: 'src',
    img: 'src',
    image: 'xlink:href'
  }
}
複製代碼
dev-client.js
dev-client.js裏面主要寫了瀏覽器端代碼,用於實現webpack的熱更新。

/* eslint-disable */
// 實現瀏覽器端的EventSource,用於跟服務器雙向通訊
// webpack熱重載客戶端跟dev-server上的熱重載插件之間須要進行雙向通訊
// 服務端webpack從新編譯後,會向客戶端推送信息,告訴客戶端進行更新
require('eventsource-polyfill')
// webpack熱重載客戶端
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')

// 客戶端收到更新動做,執行頁面刷新
hotClient.subscribe(function (event) {
  if (event.action === 'reload') {
    window.location.reload()
  }
})
複製代碼
build.js
執行」npm run build」的時候首先執行的是build/build.js文件,build.js主要完成下面幾件事:

loading動畫
刪除目標文件夾
執行webpack構建
輸出信息
說明: webpack編譯以後會輸出到配置裏面指定的目標文件夾;刪除目標文件夾以後再建立是爲了去除舊的內容,以避免產生不可預測的影響。

// 檢查NodeJS和npm的版本
require('./check-versions')()

process.env.NODE_ENV = 'production'

// ora,一個能夠在終端顯示spinner的插件
var ora = require('ora')
// rm,用於刪除文件或文件夾的插件
var rm = require('rimraf')
var path = require('path')
// chalk,用於在控制檯輸出帶顏色字體的插件
var chalk = require('chalk')
var webpack = require('webpack')
var config = require('../config')
var webpackConfig = require('./webpack.prod.conf')

var spinner = ora('building for production...')
spinner.start() // 開啓loading動畫

// 首先將整個dist文件夾以及裏面的內容刪除,以避免遺留舊的沒用的文件
// 刪除完成後纔開始webpack構建打包
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
  if (err) throw err
  // 執行webpack構建打包,完成以後在終端輸出構建完成的相關信息或者輸出報錯信息並退出程序
  webpack(webpackConfig, function (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'
    ))
  })
})

複製代碼
webpack.prod.conf.js
構建的時候用到的webpack配置來自webpack.prod.conf.js,該配置一樣是在webpack.base.conf基礎上的進一步完善。主要完成下面幾件事情:

合併基礎的webpack配置
配置樣式文件的處理規則,styleLoaders
配置webpack的輸出
配置webpack插件
gzip模式下的webpack插件配置
webpack-bundle分析
說明: webpack插件裏面多了醜化壓縮代碼以及抽離css文件等插件。

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')
// copy-webpack-plugin,用於將static中的靜態文件複製到產品文件夾dist
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// optimize-css-assets-webpack-plugin,用於優化和最小化css資源
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

var env = config.build.env

var webpackConfig = merge(baseWebpackConfig, {
  module: {
    // 樣式文件的處理規則,對css/sass/scss等不一樣內容使用相應的styleLoaders
    // 由utils配置出各類類型的預處理語言所須要使用的loader,例如sass須要使用sass-loader
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
  // 是否使用source-map
  devtool: config.build.productionSourceMap ? '#source-map' : false,
  // webpack輸出路徑和命名規則
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  // webpack插件
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    // 醜化壓縮JS代碼
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      sourceMap: true
    }),
    // extract css into its own file
    // 將css提取到單獨的文件
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css')
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    // 優化、最小化css代碼,若是隻簡單使用extract-text-plugin可能會形成css重複
    // 具體緣由能夠看npm上面optimize-css-assets-webpack-plugin的介紹
    new OptimizeCSSPlugin({
      cssProcessorOptions: {
        safe: true
      }
    }),
    // generate dist index.html with correct asset hash for caching.
    // you can customize output by editing /index.html
    // see https://github.com/ampedandwired/html-webpack-plugin
    // 將產品文件的引用注入到index.html
    new HtmlWebpackPlugin({
      filename: config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        // 刪除index.html中的註釋
        removeComments: true,
        // 刪除index.html中的空格
        collapseWhitespace: true,
        // 刪除各類html標籤屬性值的雙引號
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      // 注入依賴的時候按照依賴前後順序進行注入,好比,須要先注入vendor.js,再注入app.js
      chunksSortMode: 'dependency'
    }),
    // keep module.id stable when vender modules does not change
    new webpack.HashedModuleIdsPlugin(),
    // split vendor js into its own file
    // 將全部從node_modules中引入的js提取到vendor.js,即抽取庫文件
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    // 從vendor中提取出manifest,緣由如上
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['vendor']
    }),
    // copy custom static assets
    // 將static文件夾裏面的靜態資源複製到dist/static
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ]
})

// 若是開啓了產品gzip壓縮,則利用插件將構建後的產品文件進行壓縮
if (config.build.productionGzip) {
  // 一個用於壓縮的webpack插件
  var 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
    })
  )
}

// 若是啓動了report,則經過插件給出webpack構建打包後的產品文件分析報告
if (config.build.bundleAnalyzerReport) {
  var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

複製代碼
check-versions.js
// chalk, 用於在控制檯輸出帶顏色字體的插件
var chalk = require('chalk')
// semver, 語義化版本檢查插件(The semantic version parser used by npm)
var semver = require('semver')
var packageConfig = require('../package.json')
// shelljs, 執行Unix命令行的插件
var shell = require('shelljs')
// 開闢子進程執行指令cmd並返回結果
function exec (cmd) {
  return require('child_process').execSync(cmd).toString().trim()
}

// node和npm版本需求
var versionRequirements = [
  {
    name: 'node',
    currentVersion: semver.clean(process.version),
    versionRequirement: packageConfig.engines.node
  }
]

if (shell.which('npm')) {
  versionRequirements.push({
    name: 'npm',
    currentVersion: exec('npm --version'),
    versionRequirement: packageConfig.engines.npm
  })
}

module.exports = function () {
  var warnings = []
  // 依次判斷版本是否符合要求
  for (var i = 0; i < versionRequirements.length; i++) {
    var mod = versionRequirements[i]
    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
      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 (var i = 0; i < warnings.length; i++) {
      var warning = warnings[i]
      console.log('  ' + warning)
    }
    console.log()
    process.exit(1)
  }
}

複製代碼
config
index.js
config文件夾下最主要的文件就是index.js了,在這裏面描述了開發和構建兩種環境下的配置,前面的build文件夾下也有很多文件引用了index.js裏面的配置

// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')

module.exports = {
  // 構建產品時使用的配置
  build: {
    // 環境變量
    env: require('./prod.env'),
    // html入口文件
    index: path.resolve(__dirname, '../dist/index.html'),
    // 產品文件的存放路徑
    assetsRoot: path.resolve(__dirname, '../dist'),
    // 二級目錄,存放靜態資源文件的目錄,位於dist文件夾下
    assetsSubDirectory: 'static',
    // 發佈路徑,若是構建後的產品文件有用於發佈CDN或者放到其餘域名的服務器,能夠在這裏進行設置
    // 設置以後構建的產品文件在注入到index.html中的時候就會帶上這裏的發佈路徑
    assetsPublicPath: '/',
    // 是否使用source-map
    productionSourceMap: true,
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    // 是否開啓gzip壓縮
    productionGzip: false,
    // gzip模式下須要壓縮的文件的擴展名,設置js、css以後就只會對js和css文件進行壓縮
    productionGzipExtensions: ['js', 'css'],
    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    // 是否展現webpack構建打包以後的分析報告
    bundleAnalyzerReport: process.env.npm_config_report
  },
  // 開發過程當中使用的配置
  dev: {
    // 環境變量
    env: require('./dev.env'),
    // dev-server監聽的端口
    port: 8080,
    // 是否自動打開瀏覽器
    autoOpenBrowser: true,
    // 靜態資源文件夾
    assetsSubDirectory: 'static',
    // 發佈路徑
    assetsPublicPath: '/',
    // 代理配置表,在這裏能夠配置特定的請求代理到對應的API接口
    // 例如將'localhost:8080/api/xxx'代理到'www.example.com/api/xxx'
    proxyTable: {},
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    // 是否開啓 cssSourceMap
    cssSourceMap: false
  }
}
複製代碼
'use strict'
const path = require('path')

module.exports = {
  dev: {
    // 開發環境下面的配置
    assetsSubDirectory: 'static',//子目錄,通常存放css,js,image等文件
    assetsPublicPath: '/',//根目錄
    proxyTable: {},//可利用該屬性解決跨域的問題
    host: 'localhost', // 地址
    port: 8080, //端口號設置,端口號佔用出現問題可在此處修改
    autoOpenBrowser: false,//是否在編譯(輸入命令行npm run dev)後打開http://localhost:8080/頁面,之前配置爲true,近些版本改成false,我的偏向習慣自動打開頁面
    errorOverlay: true,//瀏覽器錯誤提示
    notifyOnErrors: true,//跨平臺錯誤提示
    poll: false, //使用文件系統(file system)獲取文件改動的通知devServer.watchOptions
    devtool: 'cheap-module-eval-source-map',//增長調試,該屬性爲原始源代碼(僅限行)不可在生產環境中使用
    cacheBusting: true,//使緩存失效
    cssSourceMap: true//代碼壓縮後進行調bug定位將很是困難,因而引入sourcemap記錄壓縮先後的位置信息記錄,當產生錯誤時直接定位到未壓縮前的位置,將大大的方便咱們調試
  },

  build: {
  // 生產環境下面的配置
    index: path.resolve(__dirname, '../dist/index.html'),//index編譯後生成的位置和名字,根據須要改變後綴,好比index.php
    assetsRoot: path.resolve(__dirname, '../dist'),//編譯後存放生成環境代碼的位置
    assetsSubDirectory: 'static',//js,css,images存放文件夾名
    assetsPublicPath: '/',//發佈的根目錄,一般本地打包dist後打開文件會報錯,此處修改成./。若是是上線的文件,可根據文件存放位置進行更改路徑
    productionSourceMap: true,
    devtool: '#source-map',////unit的gzip命令用來壓縮文件,gzip模式下須要壓縮的文件的擴展名有js和css
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    bundleAnalyzerReport: process.env.npm_config_report
  }
}
複製代碼
prod.env.js
當開發是調取dev.env.js的開發環境配置,發佈時調用prod.env.js的生產環境配置

'use strict'
module.exports = {
  NODE_ENV: '"production"'
}
複製代碼
dev.env.js
config內的文件實際上是服務於build的,大部分是定義一個變量export出去。

'use strict'//採用嚴格模式
const merge = require('webpack-merge')//
const prodEnv = require('./prod.env')
//webpack-merge提供了一個合併函數,它將數組和合並對象建立一個新對象。
//若是遇到函數,它將執行它們,經過算法運行結果,而後再次將返回的值封裝在函數中.這邊將dev和prod進行合併
module.exports = merge(prodEnv, {
  NODE_ENV: '"development"'
})
複製代碼
src
①、assets文件:腳手架自動會放入一個圖片在裏面做爲初始頁面的logo。日常咱們使用的時候會在裏面創建js,css,img,fonts等文件夾,做爲靜態資源調用

②、components文件夾:用來存放組件,合理地使用組件能夠高效地實現複用等功能,從而更好地開發項目。通常狀況下好比建立頭部組件的時候,咱們會新建一個header的文件夾,而後再新建一個header.vue的文件

③、router文件夾:該文件夾下有一個叫index.js文件,用於實現頁面的路由跳轉,具體使用請點擊→vue-router傳送門

④、App.vue:做爲咱們的主組件,可經過使用開放入口讓其餘的頁面組件得以顯示。

⑤、main.js:做爲咱們的入口文件,主要做用是初始化vue實例並使用須要的插件,小型項目省略router時可放在該處

.babelrc
{
//制定轉碼的規則
  "presets": [
  //env是使用babel-preset-env插件將js進行轉碼成es5,而且設置不轉碼的AMD,COMMONJS的模塊文件,制定瀏覽器的兼容
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
  
  "plugins": ["transform-vue-jsx", "transform-runtime"]//
}
複製代碼
.postcessrc.js
.postcssrc.js文件實際上是postcss-loader包的一個配置,在webpack的舊版本能夠直接在webpack.config.js中配置,現版本中postcss的文檔示例獨立出.postcssrc.js,裏面寫進去須要使用到的插件

module.exports = {
  "plugins": {
    "postcss-import": {},//
    "postcss-url": {},//
    "autoprefixer": {}//
  }
}
複製代碼
package.json
package.json來制定名單,須要哪些npm包來參與到項目中來,npm install命令根據這個配置文件增減來管理本地的安裝包

{
//從name到private都是package的配置信息,也就是咱們在腳手架搭建中輸入的項目描述
  "name": "shop",//項目名稱:不能以.(點)或者_(下劃線)開頭,不能包含大寫字母,具備明確的的含義與現有項目名字不重複
  "version": "1.0.0",//項目版本號:遵循「大版本.次要版本.小版本」
  "description": "A Vue.js project",//項目描述
  "author": "qietuniu",//做者名字
  "private": true,//是否私有
  //scripts中的子項便是咱們在控制檯運行的腳本的縮寫
  "scripts": {
   //①webpack-dev-server:啓動了http服務器,實現實時編譯;
   //inline模式會在webpack.config.js入口配置中新增webpack-dev-server/client?http://localhost:8080/的入口,使得咱們訪問路徑爲localhost:8080/index.html(相應的還有另一種模式Iframe);
   //progress:顯示打包的進度
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",  
    "start": "npm run dev",//與npm run dev相同,直接運行開發環境
    "build": "node build/build.js"//使用node運行build文件
  },
  //②dependencies(項目依賴庫):在安裝時使用--save則寫入到dependencies
  "dependencies": {
    "vue": "^2.5.2",//vue.js
    "vue-router": "^3.0.1"//vue的路由插件
  },
  //和devDependencies(開發依賴庫):在安裝時使用--save-dev將寫入到devDependencies
  "devDependencies": {
    "autoprefixer": "^7.1.2",//autoprefixer做爲postcss插件用來解析CSS補充前綴,例如 display: flex會補充爲display:-webkit-box;display: -webkit-flex;display: -ms-flexbox;display: flex。
    //babel:如下幾個babel開頭的都是針對es6解析的插件。用最新標準編寫的 JavaScript 代碼向下編譯成能夠在今天隨處可用的版本
    "babel-core": "^6.22.1",//babel的核心,把 js 代碼分析成 ast ,方便各個插件分析語法進行相應的處理。
    "babel-helper-vue-jsx-merge-props": "^2.0.3",//預製babel-template函數,提供給vue,jsx等使用
    "babel-loader": "^7.1.1",//使項目運行使用Babel和webpack來傳輸js文件,使用babel-core提供的api進行轉譯
    "babel-plugin-syntax-jsx": "^6.18.0",//支持jsx
    "babel-plugin-transform-runtime": "^6.22.0",//避免編譯輸出中的重複,直接編譯到build環境中
    "babel-plugin-transform-vue-jsx": "^3.5.0",//babel轉譯過程當中使用到的插件,避免重複
    "babel-preset-env": "^1.3.2",//轉爲es5,transform階段使用到的插件之一
    "babel-preset-stage-2": "^6.22.0",//ECMAScript第二階段的規範
    "chalk": "^2.0.1",//用來在命令行輸出不一樣顏色文字
    "copy-webpack-plugin": "^4.0.1",//拷貝資源和文件
    "css-loader": "^0.28.0",//webpack先用css-loader加載器去解析後綴爲css的文件,再使用style-loader生成一個內容爲最終解析完的css代碼的style標籤,放到head標籤裏
    "extract-text-webpack-plugin": "^3.0.0",//將一個以上的包裏面的文本提取到單獨文件中
    "file-loader": "^1.1.4",//③打包壓縮文件,與url-loader用法相似
    "friendly-errors-webpack-plugin": "^1.6.1",//識別某些類別的WebPACK錯誤和清理,聚合和優先排序,以提供更好的開發經驗
    "html-webpack-plugin": "^2.30.1",//簡化了HTML文件的建立,引入了外部資源,建立html的入口文件,可經過此項進行多頁面的配置
    "node-notifier": "^5.1.2",//支持使用node發送跨平臺的本地通知
    "optimize-css-assets-webpack-plugin": "^3.2.0",//壓縮提取出的css,並解決ExtractTextPlugin分離出的js重複問題(多個文件引入同一css文件)
    "ora": "^1.2.0",//加載(loading)的插件
    "portfinder": "^1.0.13",//查看進程端口
    "postcss-import": "^11.0.0",//能夠消耗本地文件、節點模塊或web_modules
    "postcss-loader": "^2.0.8",//用來兼容css的插件
    "postcss-url": "^7.2.1",//URL上從新定位、內聯或複製
    "rimraf": "^2.6.0",//節點的UNIX命令RM—RF,強制刪除文件或者目錄的命令
    "semver": "^5.3.0",//用來對特定的版本號作判斷的
    "shelljs": "^0.7.6",//使用它來消除shell腳本在UNIX上的依賴性,同時仍然保留其熟悉和強大的命令,便可執行Unix系統命令
    "uglifyjs-webpack-plugin": "^1.1.1",//壓縮js文件
    "url-loader": "^0.5.8",//壓縮文件,可將圖片轉化爲base64
    "vue-loader": "^13.3.0",//VUE單文件組件的WebPACK加載器
    "vue-style-loader": "^3.0.1",//相似於樣式加載程序,您能夠在CSS加載器以後將其連接,以將CSS動態地注入到文檔中做爲樣式標籤
    "vue-template-compiler": "^2.5.2",//這個包能夠用來預編譯VUE模板到渲染函數,以免運行時編譯開銷和CSP限制
    "webpack": "^3.6.0",//打包工具
    "webpack-bundle-analyzer": "^2.9.0",//可視化webpack輸出文件的大小
    "webpack-dev-server": "^2.9.1",//提供一個提供實時重載的開發服務器
    "webpack-merge": "^4.1.0"//它將數組和合並對象建立一個新對象。若是遇到函數,它將執行它們,經過算法運行結果,而後再次將返回的值封裝在函數中
  },
  //engines是引擎,指定node和npm版本
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  //限制了瀏覽器或者客戶端須要什麼版本纔可運行
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}
複製代碼
註釋:

①、點這裏→webpack運行時的配置文檔傳送門

②、devDependencies和dependencies的區別: devDependencies裏面的插件只用於開發環境,不用於生產環境,即輔助做用,打包的時候須要,打包完成就不須要了。而dependencies是須要發佈到生產環境的,自始至終都在。好比wepack等只是在開發中使用的包就寫入到devDependencies,而像vue這種項目全程依賴的包要寫入到dependencies

點這裏→更多安裝包文檔搜索頁傳送門

③、file-loader和url-loader的區別:以圖片爲例,file-loader可對圖片進行壓縮,可是仍是經過文件路徑進行引入,當http請求增多時會下降頁面性能,而url-loader經過設定limit參數,小於limit字節的圖片會被轉成base64的文件,大於limit字節的將進行圖片壓縮的操做。總而言之,url-loader是file-loader的上層封裝。

點這裏→file-loader 和 url-loader詳解

點這裏→file-loader文檔傳送門

點這裏→url-loader文檔傳送門

其餘文件
①、.editorconfig:編輯器的配置文件

②、.gitignore:忽略git提交的一個文件,配置以後提交時將不會加載忽略的文件

③、index.html:頁面入口,通過編譯以後的代碼將插入到這來。

④、package.lock.json:鎖定安裝時的包的版本號,而且須要上傳到git,以保證其餘人在npm install時你們的依賴能保證一致

⑤、README.md:可此填寫項目介紹

⑥、node_modules:根據package.json安裝時候生成的的依賴(安裝包)

其餘好的博客筆記
vue-cli的webpack模板項目配置文件分析

vue-cli腳手架中webpack配置基礎文件詳解
相關文章
相關標籤/搜索