vue-cli脚手架搭建

一、安装vue-cli

npm install -g vue-cli1

二、使用vue-cli创建vue项目

用法: vue init  template-name:
    . webpack
    . webpack-simple  // 一个简单webpack+vue-loader的模板,不包含其他功能。
    . browserify     //  一个全面的Browserify+vueify 的模板,功能包括热加载,linting,单元检测。
    . browserify-simple  // 一个简单Browserify+vueify的模板,不包含其他功能。
    . pwa           // 基于webpack模板的vue-cli的PWA模板
    . simple      //  一个最简单的单页应用模板123456789

常用的就是webpack了,模板之间的不同,自己体验
示例:

vue init webpack my-project1

执行指令后,会让用户输入几个基本的选项,如图所示

需要注意的是项目的名称不能大写,不然会报错。

  • Project name :项目名称 ,如果不需要更改直接回车就可以了。注意:这里不能使用大写。

  • Project description:项目描述,默认为A Vue.js project,直接回车,不用编写。

  • Author:作者,如果你有配置git,他会读取.ssh文件中的user。

  • Install vue-router? 是否安装vue的路由插件,Y代表安装,N无需安装,下面的命令也是一样的。

  • Use ESLint to lint your code? 是否用ESLint来限制你的代码错误和风格

  • setup unit tests with Karma + Mocha? 是否需要安装单元测试工具Karma+Mocha。

  • Setup e2e tests with Nightwatch?是否安装e2e来进行用户行为模拟测试。

  • Should we run npm install for you after the project has been created?(recommended)npm
     
    询问你使用npm安装还是yarn安装包依赖,我这里选择的是npm,yarn更快更好,使用yarn之前确保你的电脑已经安装yarn。

根据提示,待模板加载完成之后,执行下面两条命令

cd my-projectnpm run dev   // dev代表下图框选的内容123

出现如图,就是编译成功了,英文稍微好点,就能读懂
这时候,鼠标放到 http://localhost:8080 会提示用“Alt+点击”即可访问;
出现如图,就成功创建了项目;

三、文件目录结构

本文主要分析开发(dev)和构建(build)两个过程涉及到的文件,故下面文件结构仅列出相应的内容。

|-- 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                  // 生产环境变量|   |-- test.env.js                  // 测试脚本的配置|-- src                              // 源码目录|   |-- components                   // vue所有组件|   |-- router                       // vue的路由管理|   |-- App.vue                      // 页面入口文件|   |-- main.js                      // 程序入口文件,加载各种公共组件|-- static                           // 静态文件,比如一些图片,json数据等|-- test                             // 测试文件|   |-- e2e                          // e2e 测试|   |-- unit                         // 单元测试|-- .babelrc                         // ES6语法编译配置|-- .editorconfig                    // 定义代码格式|-- .eslintignore                    // eslint检测代码忽略的文件(夹)|-- .eslintrc.js                     // 定义eslint的plugins,extends,rules|-- .gitignore                       // git上传需要忽略的文件格式|-- .postcsssrc                      // postcss配置文件|-- README.md                        // 项目说明,markdown文档|-- index.html                       // 访问的页面|-- package.json                     // 项目基本信息,包依赖信息等12345678910111213141516171819202122232425262728293031

如图所示:


下边是具体文件的具体分析

1. package.json文件

package.json文件是项目的配置文件,定义了项目的基本信息以及项目的相关包依赖,npm运行命令等

scripts 里定义的是一些比较长的命令,用node去执行一段命令,比如

npm run dev1

其实就是执行

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

这句话的意思是利用 webpack-dev-server 读取 webpack.dev.conf.js 信息并启动一个本地服务器。

2. dependencies VS devDependencies

简单的来说

dependencies 是运行时依赖(生产环境)       npm install --save  **(package name)devDependencies 是开发时的依赖(开发环境)  npm install --save-dev  **(package name)12

3. 基础配置文件 webpack.base.conf.js

基础的 webpack 配置文件主要根据模式定义了入口出口,以及处理 vue, babel等的各种模块,是最为基础的部分。其他模式的配置文件以此为基础通过 webpack-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, '../'),  // 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  
  },  /**
   * 当webpack试图去加载模块的时候,它默认是查找以 .js 结尾的文件的,
   * 它并不知道 .vue 结尾的文件是什么鬼玩意儿,
   * 所以我们要在配置文件中告诉webpack,
   * 遇到 .vue 结尾的也要去加载,
   * 添加 resolve 配置项,如下:
   */
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {  // 创建别名      'vue$': 'vue/dist/vue.esm.js',      '@': resolve('src'),  // 如 '@/components/HelloWorld'
    }
  },  // 不同类型模块的处理规则 就是用不同的loader处理不同的文件
  module: {
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {// 对所有.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'), resolve('node_modules/webpack-dev-server/client')]
      },
      {// 对图片资源文件使用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: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]') // hash:7 代表 7 位数的 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'
  }
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109

4. 开发环境配置文件 webpack.dev.conf.js

'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')// html-webpack-plugin用于将webpack编译打包后的产品文件注入到html模板中// 即在index.html里面加上和 {
  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
      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)
    }
  })
})1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061075. 生产模式配置文件 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中的静态文件复制到产品文件夹distconst 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    // 由utils配置出各种类型的预处理语言所需要使用的loader,例如sass需要使用sass-loader
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true,
      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
    }),    // 丑化压缩JS代码    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          warnings: false
        }
      },
      sourceMap: config.build.productionSourceMap,
      parallel: true
    }),    // extract css into its own file    // 将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: {        // 删除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 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文件夹里面的静态资源复制到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 = webpackConfig1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711726. build.js 编译入口'use strict'require('./check-versions')()

process.env.NODE_ENV = 'production'// ora,一个可以在终端显示spinner的插件const ora = require('ora')// rm,用于删除文件或文件夹的插件const rm = require('rimraf')const path = require('path')// chalk,用于在控制台输出带颜色字体的插件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动画// 首先将整个dist文件夹以及里面的内容删除,以免遗留旧的没用的文件// 删除完成后才开始webpack构建打包
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {  if (err) throw err  // 执行webpack构建打包,完成之后在终端输出构建完成的相关信息或者输出报错信息并退出程序
  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') &nb

评论 (0)

发表评论