vue-cli構建項目詳解

目錄

1、Vue是什麼

2、node安裝

3、NPM

4、cli安裝

5、快速構建項目

6、vue-test目錄解析

7 、項目運行詳解

8、總結


1、Vue是什麼

vue是什麼,是一套構建用戶界面的漸進式框架

vue兩大核心思想,組件化和數據驅動,組件化就是把一個整體拆分個一個一個的組件,組件可重複使用。數據驅動是前端未來的發展方向,釋放了對DOM的操作,讓DOM隨着數據的變化而自然的變化,不必過多的關注DOM,只需要將數組組織好即可。

2、node安裝

windows環境下的node安裝是很方便的,登錄官網http://nodejs.org/,找到對應的系統版本直接下載就行.

  • 下載安裝包

LTS:追求穩定的開發用戶,可以下載這個版本,只需要每年十月一個版本的時候,進行升級。

Current:熱衷嘗試新特性,或者不在生產環境中的實現性項目可以下載這個版本。更新比較頻繁,切不保證兼容性。

  • 安裝過程

安裝的時候直接next即可,window按照過程會提示添加path的系統變量,變量是你的安裝路徑,例如C:\Program Files\nodejs

  • 測試

cmd輸入node -v 測試是否安裝成功,如果成功,會出現版本號

3、NPM

在用vue構建大型應用的時候,推薦使用npm安裝,npm能很好的喝webpack等打包工具進行配合。可以將npm鏡像設置爲淘寶npm鏡像,可以大幅度提升下載速度。詳情參考https://npm.taobao.org/

  •   npm安裝

剛纔安裝了node,最新版本的node安裝包已經集成了npm,所以安裝node的同時也已經成功安裝了npm,測試npm是否安裝成功

  • 安裝淘寶鏡像
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 安裝模塊
$ cnpm install [name]
  • 同步模塊
$ cnpm sync connect
  • 其他命令
$ cnpm info connect

4、cli安裝

Vue提供了的官方cli(命令行工具),爲單頁面應用(SPA)快速搭建繁雜的腳手架。可以幾分鐘之內快速構建一個項目運行起來

  • 全局安裝cli
npm install --global vue-cli

5、快速構建項目

  • 安裝node,npm,cli參考上文,同時在C:\Users\Andminster\AppData\Roaming\npm目錄下爲會生成幾個vue相關的文件
  • 創建自己的項目,使用命令 

在運行安裝命令以後,需要輸入一些命令,下面一個一個來解釋一下

  1. Project name  項目名稱,可以自己指定,也可以直接回車使用默認的名稱。注意這裏的名稱不能有大寫字母
  2. projuect description  (A Vue.js project),項目描述,可以隨意寫,也可以不寫
  3. Author... 作者,隨意輸入吧
  4. 選擇題:

    4.1、Runtime + Compiler: recommended for most users    運行加編譯,既然已經說了推薦,就選它了
    4.2、Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specificHTML) are ONLY allowed in .vue files - render functions are required elsewhere   僅運行時,已經有推薦了就選擇第一個了

  5. Install vue-router? (Y/n)   是否安裝vue-router 這是官方的路由,輸入y,使用官方路由

  6. Use ESLint to lint your code? (Y/n)   是否使用ESLint管理代碼,是一個代碼風格管理工具,統一整體代碼風格,不會影響整體運行

  7. Pick an ESLint preset (Use arrow keys)  選擇一個ESLint預設,編寫vue項目的代碼風格

  8. 選擇代碼標準

      8.1、Standard (https://github.com/feross/standard)    標準,有些看不明白,什麼標準呢,去給提示的standardgithub地址 看一下, 原來時js的標準風格

      8.2、AirBNB (https://github.com/airbnb/javascript)    JavaScript最合理的方法,這個github地址說的是JavaScript最合理的 方法

      8.3、none (configure it yourself)    這個不用說,自己定義風格

  9. Setup unit tests with Karma + Mocha? (Y/n)  是否安裝單元測試,我選擇安裝

  10. Setup e2e tests with Nightwatch(Y/n)?     是否安裝e2e測試 ,我選擇安裝

  11. 安裝成功

   

這幾個配置選擇yes 或者 no 對於我們項目最大的影響就是,如果選擇了yes 則生成的項目會自動有相關的配置,有一些loader我們就要配套下載。所以如果我們確定不用的話最好不要yes,要麼下一步要下很多沒有用的loader

6、vue-test目錄解析

新建項目目錄結構如圖所示:

  • build 裏面是一些操作文件,使用npm run * 執行的都是這裏面的文件,主要是進行webpack的一些配置。對我們最有用並且可能會使用的就是webpack.base.config.js、webpack.dev.config.js、webpack.prod.config.js三個webpack的配置文件,分別是基本webpack配置、開發環境配置、生產環境配置。實際上這些文件裏面的內容,一些簡單的配置都已經有了,包括入口文件、插件、loader、熱更新等都已經配置好了。我們要做的只是根據自己的項目有什麼loader需要增加的,比如生成環境需要加上UglifyJsPlugin插件等可以自行配置,或者一些插件增加或者不需要的刪除,其實都是和業務相關了,其他的都可以不需要動                            
  • config 配置文件,執行文件需要的配置信息,最主要的就是index.js 這個文件進行配置代理服務器,這個地方和我們息息相關,和後臺聯調就是在這裏設置一個地址就可以了。打開index.js 找到“proxyTable“這個屬性,然後在裏面加上對應的後臺地址即可             
  • node_modules,安裝的的模塊文件,npm install會把所有的模塊安裝下載,
  • src資源文件,所有的組件和所用的圖片都是放在這裏,assets資源文件夾,放圖片之類的資源;components,組件文件夾,寫的所有的組件放在這個下面;router路由文件夾,這個也決定了頁面的跳轉規則;APP.vue應用組件,所有自己寫的組件,都是在這個裏面運行,vue文件入口界面;main.js,對應App.vue 創建vue實例,也是入口文件,對應webpack.base.config.js裏的入口配置,webpack四大特性entry入口、output輸出、loader加載器、plugins插件。 
  • static,存放的文件不會經過webpack處理,可以直接引用,
  • test 單元測試和e2e測試的文件在此下面
  • package.json, 這個文件很重要,有2部分很有用。script裏面設置命令,例如設置了dev用於調試,執行命令npm run dev,就是執行dev對應的命令,;設置了build,執行npm run build 用於打包;另外一部分,可以看到我們的依賴包,在dependencies和devDependencies中,分別對應全局下載和局部下載的依賴包

在其他博客看到更好更直觀更詳細的的目錄解析,記錄下來,加深記憶,方便查閱。

|-- build                            // 項目構建(webpack)相關代碼
|   |-- build.js                     // 生產環境構建代碼
|   |-- check-version.js             // 檢查node、npm等版本
|   |-- utils.js                     // 構建工具相關
|   |-- vue-loader.conf.js           // webpack loader配置
|   |-- webpack.base.conf.js         // webpack基礎配置
|   |-- webpack.dev.conf.js          // webpack開發環境配置,構建開發本地服務器
|   |-- webpack.prod.conf.js         // webpack生產環境配置
|-- config                           // 項目開發環境配置
|   |-- dev.env.js                   // 開發環境變量
|   |-- index.js                     // 項目一些配置變量
|   |-- prod.env.js                  // 生產環境變量
|-- src                              // 源碼目錄
|   |-- components                   // vue公共組件
|   |-- router                       // vue的路由管理
|   |-- App.vue                      // 頁面入口文件
|   |-- main.js                      // 程序入口文件,加載各種公共組件
|-- static                           // 靜態文件,比如一些圖片,json數據等
|-- .babelrc                         // ES6語法編譯配置
|-- .editorconfig                    // 定義代碼格式
|-- .gitignore                       // git上傳需要忽略的文件格式
|-- .postcsssrc                       // postcss配置文件
|-- README.md                        // 項目說明
|-- index.html                       // 入口頁面
|-- package.json                     // 項目基本信息,包依賴信息等
--------------------- 

重點描述幾個重要文件

1、package.json文件

package.json文件是項目的配置文件,定義了項目的基本信息和相關依賴包,npm運行命令等

2. dependencies VS devDependencies

dependencies 是運行時依賴(生產環境)       npm install --save  **(package name)
devDependencies 是開發時的依賴(開發環境)  npm install --save-dev  **(package name)

dependencies是運行時候的依賴(生產環境),devDependencies是開發時候的依賴(開發環境),相應的npm install在安裝npm包的時候,有兩種命令參數可以把他們的信息寫入package.json文件,-save會把依賴包名添加到package.json文件dependencies 下面,–save-dev 則添加到 package.json 文件 devDependencies 鍵下。 
舉個例子比如我們項目要引用jQuery,因爲jQuery部署到線上環境也要使用(生產環境),所以安裝jQuery的命令爲

npm install jQuery --save

 這時候 dependencies 鍵下就會多了一個jQuery包。 

3、基礎配置文件webpack.base.config.js

基礎的webpack配置文件主要根據模式定義了入口出口,以及處理vue.babel等模塊,是最爲基礎的部分,其他模式的配置文件以此爲基礎,通過webpck-merge合併。

'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)
}
// 定義一下代碼檢測的規則
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
  }
})

module.exports = {
  context: path.resolve(__dirname, '../'),//基礎目錄
  entry: {
    app: './src/main.js'//webpack入口文件
  },
  output: {
    path: config.build.assetsRoot,//輸出目錄
    filename: '[name].js',//輸出文件名稱
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath//生產模式
      : config.dev.assetsPublicPath//開發模式
  },
  /**
  *當webpack試圖去加載模塊的時候,他默認是查找.js結尾的文件的,
  *並不知道.vue結尾的文件是什麼鬼玩意兒
  *遇到.vue結尾的文件也要去加載
  *進行如下配置
  */
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {//創建別名
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),// 如 '@/components/HelloWorld'
    }
  },
  //模塊相應的配置,包括Loader,plugin等。不同模塊的處理規則,用不同的loader處理不同的文件
  module: {
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,//vue要在babel之前,對所有的.vue文件使用vue-loader進行編譯,
        loader: 'vue-loader',//vue轉普通的html
        options: vueLoaderConfig//可選項:vue-loader選項配置
      },
      {
        test: /\.js$/,//babel
        loader: 'babel-loader',//es6 轉es5
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]// url-loader 文件大小低於指定的限制時,可返回 DataURL,即base64
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,//url-loader 圖片 對圖片資源使用url-loader
        loader: 'url-loader',
        options: {// 小於10K的圖片轉成base64編碼的dataURL字符串寫到代碼中
          limit: 10000,// 默認無限制
          name: utils.assetsPath('img/[name].[hash:7].[ext]') //其他的圖片轉移到靜態資源文件夾
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,// 對多媒體資源文件使用url-loader
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,//對字體資源文件使用url-loader
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  node: {// 是否 polyfill 或 mock
    // 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'
  }
}

4、開發環境配置文件,webpack.dev.config.js

啓動項目的時候就要用到這個文件,非常重要哦

// webpack開發環境配置
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')//基本配置的參數
const merge = require('webpack-merge')//webpack-merge是一個可以合併數組和對象的插件
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')//webpack基本配置文件,開發和運行時候公用
const CopyWebpackPlugin = require('copy-webpack-plugin')

/**
* HtmlWebpackPlugin description
* 這個插件的作用是依據一個簡單模板,幫你生成最終的html5文件
* 這個文件中自動引用了打包以後的js文件,每次編譯都在文件名中插入了一個不同的哈希值
* 即在index.html裏面加上<link>和<script>標籤引用webpack打包後的文件
*/
const HtmlWebpackPlugin = require('html-webpack-plugin')
//能夠更好的再終端看到webpack運行時候的錯誤和警告
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
//自動檢索下一個可用的端口
const portfinder = require('portfinder')
// 讀取系統環境變量的host
const HOST = process.env.HOST
// 讀取系統環境變量的port
const PORT = process.env.PORT && Number(process.env.PORT)
//合併baseWebpackConfig配置
const devWebpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  },
  // cheap-module-eval-source-map is faster for development 添加元信息(meta info)增強調試
  devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js 
  ///webpack-dev-server服務器配置
  devServer: {
    clientLogLevel: 'warning',//console控制檯顯示的消息,
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
      ],
    },
    hot: true,//開啓熱加載
    contentBase: false, // since we use CopyWebpackPlugin. 
    compress: true,//開啓壓縮
    host: HOST || config.dev.host,//HOST 優先
    port: PORT || config.dev.port,//PORT 優先
    open: config.dev.autoOpenBrowser,//自動打開瀏覽器,這裏是默認是false,所以不會自動打開
    overlay: config.dev.errorOverlay// warning 和 error 都要顯示
      ? { warnings: false, errors: true }
      : false,
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,//設置代理,用於前後端分離,
    quiet: true, // necessary for FriendlyErrorsPlugin
    watchOptions: {//啓用watch模式,在初始構建之後,webpack將繼續監聽任何已解析的文件的更改
      poll: config.dev.poll,//通過傳遞true,開啓polling.或者指定毫秒爲單位進行輪詢
    }
  },
  plugins: [//webpack一些構建用到的插件
    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
    new HtmlWebpackPlugin({
      // 指定編譯後生成的html文件
      filename: 'index.html',
      // 需要處理的模板
      template: 'index.html',
      // 打包過程中輸出的js、css的路徑添加到html文件中
      // css文件插入到head中
      // js文件插入到body中,可能的選項有 true, 'head', 'body', false
      inject: true
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ]
})

module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port //獲取當前設定的端口
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests 發佈新的端口,對於e2e進行測試
      process.env.PORT = port
      // add port to devServer config 設置devServer端口
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      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)
    }
  })
})

5、生產模式配置文件webpack.prod.conf.js

// webpack生產環境配置
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
// copy-webpack-plugin ,用於static的靜態資源文件夾複製到產品文件夾dist.
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
// optimize-css-assets-webpack-plugin 優化和最小化css文件
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
// uglifyJs 混淆js插件
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const env = process.env.NODE_ENV === 'testing'
  ? require('../config/test.env')
  : require('../config/prod.env')

const webpackConfig = merge(baseWebpackConfig, {
  module: {
    /**
    *樣式文件的處理規則,對css sass scss等不同內容使用相應的styleloaders
    *utile配置出各種預處理語言使用的loader
    */
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,//production 下生成 sourceMap
      extract: true,//util 中 styleLoaders 方法內的 generateLoaders 函數
      usePostCSS: true
    })
  },
  devtool: config.build.productionSourceMap ? config.build.devtool : false,
   // webpack輸出路徑和命名規則
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new UglifyJsPlugin({//js 代碼壓縮還可配置 include, cache 等,也可用 babel-minify 醜化壓縮JS代碼
      uglifyOptions: {
        compress: {
          warnings: false
        }
      },
      sourceMap: config.build.productionSourceMap,
      parallel: true// 充分利用多核cpu
    }),
    // extract css into its own file 提取文件中的css 將css提取到單獨的文件
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      // Setting the following option to `false` will not extract CSS from codesplit chunks.
      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
      allChunks: true,
    }),
    // 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: config.build.productionSourceMap
        ? { safe: true, map: { inline: false } }
        : { 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: process.env.NODE_ENV === 'testing'
        ? 'index.html'
        : config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        // 刪除inde.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 vendor modules does not change  按 dependency 的順序引入
    new webpack.HashedModuleIdsPlugin(),
    // enable scope hoisting
    new webpack.optimize.ModuleConcatenationPlugin(),
    // split vendor js into its own file
     // 從vendor中提取出manifest,原因如上
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        // 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
    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
    }),

    // 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插件
  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
    })
  )
}
// 如果啓動了report,則通過插件給出webpack構建打包後的產品文件分析報告
if (config.build.bundleAnalyzerReport) {
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

6、build.js編譯入口

'use strict'
require('./check-versions')()

process.env.NODE_ENV = 'production'//設置當前環境爲生產環境

const ora = require('ora')//loading.. 進度條
const rm = require('rimraf')//刪除文件
const path = require('path')
const chalk = require('chalk')//顏色設置
const webpack = require('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
    // 刪除完成回調函數內,執行編譯
   webpack(webpackConfig, (err, stats) => {
    spinner.stop()
    if (err) throw err
        // 編譯完成,輸出文件
    process.stdout.write(stats.toString({
      colors: true,
      modules: false,
      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
      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'
    ))
  })
})

7. 實用代碼段 utils.js

'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')

exports.assetsPath = function (_path) {
  const assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory

  return path.posix.join(assetsSubDirectory, _path)//posix方法修正路徑
}
/**
* options
* 示例: ({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
*/
exports.cssLoaders = function (options) {
  options = options || {}

  const cssLoader = {
    loader: 'css-loader',
    options: {
      sourceMap: options.sourceMap
    }
  }

  const postcssLoader = {
    loader: 'postcss-loader',
    options: {
      sourceMap: options.sourceMap
    }
  }

  // generate loader string to be used with extract text plugin
  function generateLoaders (loader, loaderOptions) {
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }

    // Extract CSS when that option is specified  生產模式中提取css
    // (which is the case during production build)
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
  }

  // https://vue-loader.vuejs.org/en/configurations/extract-css.html 
  // 返回各種 loaders 對象
  return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
  }
}

// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
  const output = []
  const loaders = exports.cssLoaders(options)

  for (const extension in loaders) {
    const loader = loaders[extension]
    output.push({
      test: new RegExp('\\.' + extension + '$'),
      use: loader
    })
  }

  return output
}
// 配合 friendly-errors-webpack-plugin
exports.createNotifierCallback = () => {
  // 基本用法:notifier.notify('message');
  const notifier = require('node-notifier')
   // 當前設定是隻有出現 error 錯誤時觸發 notifier 發送通知
  return (severity, errors) => {
    if (severity !== 'error') return //嚴重程度可以是 'error' 或 'warning'

    const error = errors[0]
    const filename = error.file && error.file.split('!').pop()

    notifier.notify({
      title: packageConfig.name,
      message: severity + ': ' + error.name,
      subtitle: filename || '',
      icon: path.join(__dirname, 'logo.png')
    })
  }
}

8、babel配置文件.babelrc

{//設定轉碼規則
  "presets": [
    ["env", {
      "modules": false,
      //對BABEL_ENV或者NODE_ENV指定的不同的環境變量,進行不同的編譯操作
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
  //轉碼用的插件
  "plugins": ["transform-vue-jsx", "transform-runtime"],
  "env": {
    "test": {
      "presets": ["env", "stage-2"],
      "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
    }
  }
}

9、編碼規範.editorconfig

root = true

[*]    // 對所有文件應用下面的規則
charset = utf-8                    // 編碼規則用utf-8
indent_style = space               // 縮進用空格
indent_size = 2                    // 縮進數量爲2個空格
end_of_line = lf                   // 換行符格式
insert_final_newline = true        // 是否在文件的最後插入一個空行
trim_trailing_whitespace = true    // 是否刪除行尾的空格

10、 .src/main.js文件解讀 

main.js是整個項目的入口文件

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

//生產環境提示,這裏設置成了false
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>' ///引入App組件
})

11、.src/app.vue文件解讀

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

template標籤包裹的內容:模板htmldom的結構

script標籤包含的js內容,可以在這裏寫一些頁面的js邏輯代碼

style樣式文件

12、 src/router/index.js 路由文件

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [//配置路由
    {
      path: '/',//訪問路徑
      name: 'HelloWorld',//訪問名稱
      component: HelloWorld//路由需要的組件
    }
  ]
})

 

7 、項目運行詳解

創建好項目以後,進入到vue-test目錄,運行如下命令,啓動項目。

cd vue-test
npm run dev

瀏覽器輸入地址:localhost:8081 打開頁面(默認端口:8080)

啓動成功以後沒有默認打開瀏覽器,木關係,修改一下配置文件。找到根目錄文件package.json-->script-->dev,在命令行中增加open命令,默認啓動的時候打開瀏覽器

8、總結

構建項目總結起來一共只有四步

  1. 安裝node、npm
  2. npm install --global vue-cli 下載vue-cil腳手架
  3. vue init webpack vue-test 生成項目,形成基本結構
  4. npm run dev 運行
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章