這可能是vue-cli最全的解析了……


title: 這可能是vue-cli最全的解析了……

date: 2018-06-17 10:00:07

tags:

  • 前端

  • vue

  • vue-cli

  • webpack


題言:

相信很多vue新手,都像我一樣卸例,只是知道可以用vue-cli直接生成一個(gè)vue項(xiàng)目的架構(gòu)趟脂,并不明白蝴光,他究竟是怎么運(yùn)行的,現(xiàn)在我們一起來研究一下尽楔。繁涂。。

一、安裝vue-cli瑞妇,相信你既然會(huì)用到vue-cli稿静,自然node環(huán)境是OK的,直接命令行下安裝

npm install -g vue-cli

二辕狰、使用vue-cli創(chuàng)建vue項(xiàng)目

用法: vue init

template-name:

        . webpack

        . webpack-simple  // 一個(gè)簡單webpack+vue-loader的模板改备,不包含其他功能。

        . browserify    //  一個(gè)全面的Browserify+vueify 的模板蔓倍,功能包括熱加載悬钳,linting,單元檢測(cè)。

        . browserify-simple  // 一個(gè)簡單Browserify+vueify的模板偶翅,不包含其他功能默勾。

        . pwa          // 基于webpack模板的vue-cli的PWA模板

        . simple      //  一個(gè)最簡單的單頁應(yīng)用模板 

常用的就是webpack了,模板之間的不同聚谁,自己體驗(yàn)

示例:

vue init webpack my-project

執(zhí)行指令后母剥,會(huì)讓用戶輸入幾個(gè)基本的選項(xiàng),如圖所示

image

需要注意的是項(xiàng)目的名稱不能大寫形导,不然會(huì)報(bào)錯(cuò)环疼。

  • Project name :項(xiàng)目名稱 ,如果不需要更改直接回車就可以了朵耕。注意:這里不能使用大寫炫隶。

  • Project description:項(xiàng)目描述,默認(rèn)為A Vue.js project,直接回車阎曹,不用編寫等限。

  • Author:作者,如果你有配置git芬膝,他會(huì)讀取.ssh文件中的user望门。

  • Install vue-router? 是否安裝vue的路由插件,Y代表安裝锰霜,N無需安裝筹误,下面的命令也是一樣的。

  • Use ESLint to lint your code? 是否用ESLint來限制你的代碼錯(cuò)誤和風(fēng)格

  • setup unit tests with Karma + Mocha? 是否需要安裝單元測(cè)試工具Karma+Mocha癣缅。

  • Setup e2e tests with Nightwatch?是否安裝e2e來進(jìn)行用戶行為模擬測(cè)試厨剪。

  • Should we run npm install for you after the project has been created?(recommended)npm

詢問你使用npm安裝還是yarn安裝包依賴,我這里選擇的是npm友存,yarn更快更好祷膳,使用yarn之前確保你的電腦已經(jīng)安裝yarn。

根據(jù)提示屡立,待模板加載完成之后,執(zhí)行下面兩條命令


cd my-project

npm run dev  // dev代表下圖框選的內(nèi)容

image

出現(xiàn)如圖直晨,就是編譯成功了,英文稍微好點(diǎn),就能讀懂

這時(shí)候勇皇,鼠標(biāo)放到 http://localhost:8080 會(huì)提示用“Alt+點(diǎn)擊”即可訪問罩句;

出現(xiàn)如圖,就成功創(chuàng)建了項(xiàng)目敛摘;

image

三门烂、文件目錄結(jié)構(gòu)

本文主要分析開發(fā)(dev)和構(gòu)建(build)兩個(gè)過程涉及到的文件,故下面文件結(jié)構(gòu)僅列出相應(yīng)的內(nèi)容兄淫。


|-- build                            // 項(xiàng)目構(gòu)建(webpack)相關(guān)代碼

|  |-- build.js                    // 生產(chǎn)環(huán)境構(gòu)建代碼

|  |-- check-version.js            // 檢查node屯远、npm等版本

|  |-- utils.js                    // 構(gòu)建工具相關(guān)

|  |-- vue-loader.conf.js          // webpack loader配置

|  |-- webpack.base.conf.js        // webpack基礎(chǔ)配置

|  |-- webpack.dev.conf.js          // webpack開發(fā)環(huán)境配置,構(gòu)建開發(fā)本地服務(wù)器

|  |-- webpack.prod.conf.js        // webpack生產(chǎn)環(huán)境配置

|-- config                          // 項(xiàng)目開發(fā)環(huán)境配置

|  |-- dev.env.js                  // 開發(fā)環(huán)境變量

|  |-- index.js                    // 項(xiàng)目一些配置變量

|  |-- prod.env.js                  // 生產(chǎn)環(huán)境變量

|  |-- test.env.js                  // 測(cè)試腳本的配置

|-- src                              // 源碼目錄

|  |-- components                  // vue所有組件

|  |-- router                      // vue的路由管理

|  |-- App.vue                      // 頁面入口文件

|  |-- main.js                      // 程序入口文件,加載各種公共組件

|-- static                          // 靜態(tài)文件捕虽,比如一些圖片氓润,json數(shù)據(jù)等

|-- test                            // 測(cè)試文件

|  |-- e2e                          // e2e 測(cè)試

|  |-- unit                        // 單元測(cè)試

|-- .babelrc                        // ES6語法編譯配置

|-- .editorconfig                    // 定義代碼格式

|-- .eslintignore                    // eslint檢測(cè)代碼忽略的文件(夾)

|-- .eslintrc.js                    // 定義eslint的plugins,extends,rules

|-- .gitignore                      // git上傳需要忽略的文件格式

|-- .postcsssrc                      // postcss配置文件

|-- README.md                        // 項(xiàng)目說明,markdown文檔

|-- index.html                      // 訪問的頁面

|-- package.json                    // 項(xiàng)目基本信息,包依賴信息等

如圖所示:

image

下邊是具體文件的具體分析

1. package.json文件

package.json文件是項(xiàng)目的配置文件薯鳍,定義了項(xiàng)目的基本信息以及項(xiàng)目的相關(guān)包依賴,npm運(yùn)行命令等

image

scripts 里定義的是一些比較長的命令挨措,用node去執(zhí)行一段命令挖滤,比如

npm run dev

其實(shí)就是執(zhí)行

webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

這句話的意思是利用 webpack-dev-server 讀取 webpack.dev.conf.js 信息并啟動(dòng)一個(gè)本地服務(wù)器。

2. dependencies VS devDependencies

簡單的來說


dependencies 是運(yùn)行時(shí)依賴(生產(chǎn)環(huán)境)      npm install --save  **(package name)

devDependencies 是開發(fā)時(shí)的依賴(開發(fā)環(huán)境)  npm install --save-dev  **(package name)

3. 基礎(chǔ)配置文件 webpack.base.conf.js

基礎(chǔ)的 webpack 配置文件主要根據(jù)模式定義了入口出口浅役,以及處理 vue, babel等的各種模塊斩松,是最為基礎(chǔ)的部分。其他模式的配置文件以此為基礎(chǔ)通過 webpack-merge 合并觉既。


'use strict'

const path = require('path')

const utils = require('./utils')

const config = require('../config')

const vueLoaderConfig = require('./vue-loader.conf')

// 獲取絕對(duì)路徑

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 = {

  // 基礎(chǔ)上下文

  context: path.resolve(__dirname, '../'),

  // webpack的入口文件

  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 

  },

  /**

  * 當(dāng)webpack試圖去加載模塊的時(shí)候惧盹,它默認(rèn)是查找以 .js 結(jié)尾的文件的,

  * 它并不知道 .vue 結(jié)尾的文件是什么鬼玩意兒瞪讼,

  * 所以我們要在配置文件中告訴webpack钧椰,

  * 遇到 .vue 結(jié)尾的也要去加載,

  * 添加 resolve 配置項(xiàng)符欠,如下:

  */

  resolve: {

    extensions: ['.js', '.vue', '.json'],

    alias: {  // 創(chuàng)建別名

      'vue$': 'vue/dist/vue.esm.js',

      '@': resolve('src'),  // 如 '@/components/HelloWorld'

    }

  },

  // 不同類型模塊的處理規(guī)則 就是用不同的loader處理不同的文件

  module: {

    rules: [

      ...(config.dev.useEslint ? [createLintingRule()] : []),

      {// 對(duì)所有.vue文件使用vue-loader進(jìn)行編譯

        test: /\.vue$/,

        loader: 'vue-loader',

        options: vueLoaderConfig

      },

      {// 對(duì)src和test文件夾下的.js文件使用babel-loader將es6+的代碼轉(zhuǎn)成es5

        test: /\.js$/,

        loader: 'babel-loader',

        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]

      },

      {// 對(duì)圖片資源文件使用url-loader

        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,

        loader: 'url-loader',

        options: {

          // 小于10K的圖片轉(zhuǎn)成base64編碼的dataURL字符串寫到代碼中

          limit: 10000,

          // 其他的圖片轉(zhuǎn)移到靜態(tài)資源文件夾

          name: utils.assetsPath('img/[name].[hash:7].[ext]')

        }

      },

      {// 對(duì)多媒體資源文件使用url-loader

        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,

        loader: 'url-loader',

        options: {

          // 小于10K的資源轉(zhuǎn)成base64編碼的dataURL字符串寫到代碼中

          limit: 10000,

          // 其他的資源轉(zhuǎn)移到靜態(tài)資源文件夾

          name: utils.assetsPath('media/[name].[hash:7].[ext]')

        }

      },

      {// 對(duì)字體資源文件使用url-loader

        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,

        loader: 'url-loader',

        options: {

          limit: 10000,

          name: utils.assetsPath('fonts/[name].[hash:7].[ext]') // hash:7 代表 7 位數(shù)的 hash

        }

      }

    ]

  },

  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'

  }

}

4. 開發(fā)環(huán)境配置文件 webpack.dev.conf.js


'use strict'

const utils = require('./utils')

const webpack = require('webpack')

const config = require('../config')  // 基本配置的參數(shù)

const merge = require('webpack-merge') // webpack-merge是一個(gè)可以合并數(shù)組和對(duì)象的插件

const path = require('path')

const baseWebpackConfig = require('./webpack.base.conf') // webpack基本配置文件(開發(fā)和生產(chǎn)環(huán)境公用部分)

const CopyWebpackPlugin = require('copy-webpack-plugin')

// html-webpack-plugin用于將webpack編譯打包后的產(chǎn)品文件注入到html模板中

// 即在index.html里面加上和標(biāo)簽引用webpack打包后的文件

const HtmlWebpackPlugin = require('html-webpack-plugin')

// friendly-errors-webpack-plugin用于更友好地輸出webpack的警告嫡霞、錯(cuò)誤等信息

const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

const portfinder = require('portfinder') // 自動(dòng)檢索下一個(gè)可用端口

const HOST = process.env.HOST

const PORT = process.env.PORT && Number(process.env.PORT) ) // 讀取系統(tǒng)環(huán)境變量的port

// 合并baseWebpackConfig配置

const devWebpackConfig = merge(baseWebpackConfig, {

  module: {

    // 對(duì)一些獨(dú)立的css文件以及它的預(yù)處理文件做一個(gè)編譯

    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })

  },

  // cheap-module-eval-source-map is faster for development

  devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js

  devServer: {  //  webpack-dev-server服務(wù)器配置

    clientLogLevel: 'warning', // console 控制臺(tái)顯示的消息,可能的值有 none, error, warning 或者 info

    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, // process.env 優(yōu)先

    port: PORT || config.dev.port, // process.env 優(yōu)先

    open: config.dev.autoOpenBrowser,

    overlay: config.dev.errorOverlay

      ? { warnings: false, errors: true }

      : false,

    publicPath: config.dev.assetsPublicPath,

    proxy: config.dev.proxyTable, // 代理設(shè)置

    quiet: true, // necessary for FriendlyErrorsPlugin

    watchOptions: { // 啟用 Watch 模式希柿。這意味著在初始構(gòu)建之后诊沪,webpack 將繼續(xù)監(jiān)聽任何已解析文件的更改

      poll: config.dev.poll, // 通過傳遞 true 開啟 polling,或者指定毫秒為單位進(jìn)行輪詢曾撤。默認(rèn)為false

    }

  },

  plugins: [

    new webpack.DefinePlugin({

      'process.env': require('../config/dev.env')

    }),

    /*模塊熱替換它允許在運(yùn)行時(shí)更新各種模塊端姚,而無需進(jìn)行完全刷新*/

    new webpack.HotModuleReplacementPlugin(),

    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.

    new webpack.NoEmitOnErrorsPlugin(),// 跳過編譯時(shí)出錯(cuò)的代碼并記錄下來,主要作用是使編譯后運(yùn)行時(shí)的包不出錯(cuò)

    // https://github.com/ampedandwired/html-webpack-plugin

    new HtmlWebpackPlugin({

    // 指定編譯后生成的html文件名

      filename: 'index.html',

      // 需要處理的模板

      template: 'index.html',

      // 打包過程中輸出的js挤悉、css的路徑添加到html文件中

      // css文件插入到head中

      // js文件插入到body中渐裸,可能的選項(xiàng)有 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 // 獲取當(dāng)前設(shè)定的端口

  portfinder.getPort((err, port) => {

    if (err) {

      reject(err)

    } else {

      // publish the new Port, necessary for e2e tests  發(fā)布新的端口,對(duì)于e2e測(cè)試

      process.env.PORT = port

      // add port to devServer config

      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. 生產(chǎn)模式配置文件 webpack.prod.conf.js


'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中的靜態(tài)文件復(fù)制到產(chǎn)品文件夾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橄仆,用于優(yōu)化和最小化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: {

    // 樣式文件的處理規(guī)則剩膘,對(duì)css/sass/scss等不同內(nèi)容使用相應(yīng)的styleLoaders

    // 由utils配置出各種類型的預(yù)處理語言所需要使用的loader,例如sass需要使用sass-loader

    rules: utils.styleLoaders({

      sourceMap: config.build.productionSourceMap,

      extract: true,

      usePostCSS: true

    })

  },

  devtool: config.build.productionSourceMap ? config.build.devtool : false,

  // webpack輸出路徑和命名規(guī)則

  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

    }),

    // 丑化壓縮JS代碼

    new UglifyJsPlugin({

      uglifyOptions: {

        compress: {

          warnings: false

        }

      },

      sourceMap: config.build.productionSourceMap,

      parallel: true

    }),

    // extract css into its own file

    // 將css提取到單獨(dú)的文件

    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.

    // 優(yōu)化盆顾、最小化css代碼怠褐,如果只簡單使用extract-text-plugin可能會(huì)造成css重復(fù)

    // 具體原因可以看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

    // 將產(chǎn)品文件的引用注入到index.html

    new HtmlWebpackPlugin({

      filename: process.env.NODE_ENV === 'testing'

        ? 'index.html'

        : config.build.index,

      template: 'index.html',

      inject: true,

      minify: {

        // 刪除index.html中的注釋

        removeComments: true,

        // 刪除index.html中的空格

        collapseWhitespace: true,

        // 刪除各種html標(biāo)簽屬性值的雙引號(hào)

        removeAttributeQuotes: true

        // more options:

        // https://github.com/kangax/html-minifier#options-quick-reference

      },

      // necessary to consistently work with multiple chunks via CommonsChunkPlugin

      // 注入依賴的時(shí)候按照依賴先后順序進(jìn)行注入,比如您宪,需要先注入vendor.js奈懒,再注入app.js

      chunksSortMode: 'dependency'

    }),

    // keep module.id stable when vendor modules does not change

    new webpack.HashedModuleIdsPlugin(),

    // enable scope hoisting

    new webpack.optimize.ModuleConcatenationPlugin(),

    // split vendor js into its own file

    // 將所有從node_modules中引入的js提取到vendor.js,即抽取庫文件

    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

    // 從vendor中提取出manifest宪巨,原因如上

    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文件夾里面的靜態(tài)資源復(fù)制到dist/static

    new CopyWebpackPlugin([

      {

        from: path.resolve(__dirname, '../static'),

        to: config.build.assetsSubDirectory,

        ignore: ['.*']

      }

    ])

  ]

})

// 如果開啟了產(chǎn)品gzip壓縮磷杏,則利用插件將構(gòu)建后的產(chǎn)品文件進(jìn)行壓縮

if (config.build.productionGzip) {

  // 一個(gè)用于壓縮的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

    })

  )

}

// 如果啟動(dòng)了report,則通過插件給出webpack構(gòu)建打包后的產(chǎn)品文件分析報(bào)告

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'

// ora,一個(gè)可以在終端顯示spinner的插件

const ora = require('ora')

// rm铝耻,用于刪除文件或文件夾的插件

const rm = require('rimraf')

const path = require('path')

// chalk盖袭,用于在控制臺(tái)輸出帶顏色字體的插件

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() // 開啟loading動(dòng)畫

// 首先將整個(gè)dist文件夾以及里面的內(nèi)容刪除,以免遺留舊的沒用的文件

// 刪除完成后才開始webpack構(gòu)建打包

rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {

  if (err) throw err

  // 執(zhí)行webpack構(gòu)建打包遥金,完成之后在終端輸出構(gòu)建完成的相關(guān)信息或者輸出報(bào)錯(cuò)信息并退出程序

  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. 實(shí)用代碼段 utils.js


'use strict'

const path = require('path')

const config = require('../config')

// extract-text-webpack-plugin可以提取bundle中的特定文本,將提取后的文本單獨(dú)存放到另外的文件

// 這里用來提取css樣式

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)

}

// 生成css蒜田、sass稿械、scss等各種用來編寫樣式的語言所對(duì)應(yīng)的loader配置

exports.cssLoaders = function (options) {

  options = options || {}

  // css-loader配置

  const cssLoader = {

    loader: 'css-loader',

    options: {

      // 是否使用source-map

      sourceMap: options.sourceMap

    }

  }

  const postcssLoader = {

    loader: 'postcss-loader',

    options: {

      sourceMap: options.sourceMap

    }

  }

  // generate loader string to be used with extract text plugin

  // 生成各種loader配置,并且配置了extract-text-pulgin

  function generateLoaders (loader, loaderOptions) {

    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

    // 例如generateLoaders('less')冲粤,這里就會(huì)push一個(gè)less-loader

    // less-loader先將less編譯成css美莫,然后再由css-loader去處理css

    // 其他sass、scss等語言也是一樣的過程

    if (loader) {

      loaders.push({

        loader: loader + '-loader',

        options: Object.assign({}, loaderOptions, {

          sourceMap: options.sourceMap

        })

      })

    }

    // Extract CSS when that option is specified

    // (which is the case during production build)

    if (options.extract) {

      // 配置extract-text-plugin提取樣式

      return ExtractTextPlugin.extract({

        use: loaders,

        fallback: 'vue-style-loader'

      })

    } else {

      // 無需提取樣式則簡單使用vue-style-loader配合各種樣式loader去處理里面的樣式

      return ['vue-style-loader'].concat(loaders)

    }

  }

  // https://vue-loader.vuejs.org/en/configurations/extract-css.html

  // 得到各種不同處理樣式的語言所對(duì)應(yīng)的loader

  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)

// 生成處理單獨(dú)的.css梯捕、.sass厢呵、.scss等樣式文件的規(guī)則

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

}

exports.createNotifierCallback = () => {

  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: path.join(__dirname, 'logo.png')

    })

  }

}

8. babel配置文件.babelrc


{ //設(shè)定轉(zhuǎn)碼規(guī)則

  "presets": [

    ["env", {

      "modules": false,

      //對(duì)BABEL_ENV或者NODE_ENV指定的不同的環(huán)境變量,進(jìn)行不同的編譯操作

      "targets": {

        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]

      }

    }],

    "stage-2"

  ],

  //轉(zhuǎn)碼用的插件

  "plugins": ["transform-vue-jsx", "transform-runtime"]

}

9 .編碼規(guī)范.editorconfig (自定義)


root = true

[*]    // 對(duì)所有文件應(yīng)用下面的規(guī)則

charset = utf-8                    // 編碼規(guī)則用utf-8

indent_style = space              // 縮進(jìn)用空格

indent_size = 2                    // 縮進(jìn)數(shù)量為2個(gè)空格

end_of_line = lf                  // 換行符格式

insert_final_newline = true        // 是否在文件的最后插入一個(gè)空行

trim_trailing_whitespace = true    // 是否刪除行尾的空格

10 .src/app.vue文件解讀


[圖片上傳失敗...(image-a4c267-1543308446355)]

export default {

  name: 'app'

}

#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;

}

標(biāo)簽包裹的內(nèi)容:這是模板的HTMLDom結(jié)構(gòu)

    標(biāo)簽包括的js內(nèi)容:你可以在這里寫一些頁面的js的邏輯代碼傀顾。

      標(biāo)簽包裹的css內(nèi)容:頁面需要的CSS樣式述吸。

11. src/router/index.js 路由文件


import Vue from 'vue'

import Router from 'vue-router'

import Hello from '@/components/Hello'

Vue.use(Router)

export default new Router({

  routes: [//配置路由

    {

      path: '/',        //訪問路徑

      name: 'Hello',    //路由名稱

      component: Hello  //路由需要的組件(駝峰式命名)

    }

  ]

12. eslint的相關(guān)配置(按照AirBnb的規(guī)則檢測(cè));

網(wǎng)上看了張挺有意思的圖:

vue-cli項(xiàng)目圖:

vue-cli項(xiàng)目圖

寫在最后: 關(guān)于配置文件的注釋都寫在代碼里了锣笨,可以單獨(dú)Copy出來看蝌矛,有什么好的想法或者建議,可以加我微信错英,歡迎交流……

image

參考文章:

1. vue-cli

2. webpack-dev-server

3. vue-cli項(xiàng)目結(jié)構(gòu)詳解

4. vue-cli的webpack模板項(xiàng)目配置

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末入撒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子椭岩,更是在濱河造成了極大的恐慌茅逮,老刑警劉巖璃赡,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異献雅,居然都是意外死亡碉考,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門挺身,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侯谁,“玉大人,你說我怎么就攤上這事章钾∏郊” “怎么了?”我有些...
    開封第一講書人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵贱傀,是天一觀的道長惨撇。 經(jīng)常有香客問我,道長府寒,這世上最難降的妖魔是什么魁衙? 我笑而不...
    開封第一講書人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮株搔,結(jié)果婚禮上剖淀,老公的妹妹穿的比我還像新娘。我一直安慰自己邪狞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開白布茅撞。 她就那樣靜靜地躺著帆卓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪米丘。 梳的紋絲不亂的頭發(fā)上剑令,一...
    開封第一講書人閱讀 49,906評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音拄查,去河邊找鬼吁津。 笑死,一個(gè)胖子當(dāng)著我的面吹牛堕扶,可吹牛的內(nèi)容都是我干的碍脏。 我是一名探鬼主播,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼稍算,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼典尾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起糊探,我...
    開封第一講書人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤钾埂,失蹤者是張志新(化名)和其女友劉穎河闰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褥紫,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姜性,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了髓考。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片部念。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绳军,靈堂內(nèi)的尸體忽然破棺而出印机,到底是詐尸還是另有隱情,我是刑警寧澤门驾,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布射赛,位于F島的核電站,受9級(jí)特大地震影響奶是,放射性物質(zhì)發(fā)生泄漏楣责。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一聂沙、第九天 我趴在偏房一處隱蔽的房頂上張望秆麸。 院中可真熱鬧,春花似錦及汉、人聲如沸沮趣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽房铭。三九已至,卻和暖如春温眉,著一層夾襖步出監(jiān)牢的瞬間缸匪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來泰國打工类溢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凌蔬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓闯冷,卻偏偏與公主長得像砂心,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛇耀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • http://click.aliyun.com/m/1000005928/題言: 相信很多vue新手计贰,都像我一樣,...
    rewq123閱讀 496評(píng)論 0 0
  • 1 Webpack 1.1 概念簡介 1.1.1 WebPack是什么 1蒂窒、一個(gè)打包工具 2躁倒、一個(gè)模塊加載工具 3...
    Kevin_Junbaozi閱讀 6,645評(píng)論 0 16
  • 一直想寫webpack的知識(shí)點(diǎn)荞怒,卻發(fā)現(xiàn)webpack其實(shí)要將webpack說的具體內(nèi)容還是挺多的。而且網(wǎng)上上一搜w...
    神秘者007閱讀 431評(píng)論 0 1
  • 今天犯了一個(gè)“不可與言而與之言”的低級(jí)錯(cuò)誤秧秉。反省一下自己! 坐朋友車一起出門辦事褐桌,突然右側(cè)車輛左轉(zhuǎn)彎,不可...
    傳馨閱讀 240評(píng)論 0 1
  • 突然就想起好友列表里有這么一位好友象迎,每次發(fā)照片他總是會(huì)在瀏覽了無數(shù)次荧嵌,空間訪客記錄顯示了好多次訪問之后評(píng)論:你這照...
    木易銘閱讀 338評(píng)論 0 1