vue-cli解析

前言

这篇文章的主题是vue-cli的理解。或许,很多人在开发vue的时候,我们会发现一个问题——只会去用,而不明白它的里面的东西。现在的框架可以说是足够的优秀,让开发者不用为搭建开发环境而烦恼。但是有时候,我们还是得回到原始生活体验一下,才能够让自己更上层楼,希望大家共勉。

正文

首先,我们来说一下安装的东西吧!处于有头有尾的目的,还是几句话草草了事。步骤如下:

  • 安装vue-cli
    npm install vue-cli -g
  • 以webpack模版安装目录
    vue init webapck webpack-template
    这样之后,我们就可以使用IDE打开目录了。

此处注明我的vue-cli的版本2.9.2,以免之后改版之后,误导读者。
之后,附上自己的目录截图,并没有做改动,如图:

在这里插入图片描述
首先,第一个问题,从何看起呢?当然,是从webpack.base.conf.js开始看起了。这个是dev和prod环境都会去加载的东西。然后,我们可以先从webpack.base.conf.js中会被用到的几个文件看起。其实,base中被用到了如下的文件,我们可以从代码中看出:

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

分别是:

  • path【路径模块】
  • build目录中的utils.js文件
  • config目录中的index文件
  • build目录中的vue-loader.conf.js文件

path路径
这个模块可以看nodejs官网的介绍,其实,就是一个文件路径的获取和设置等模块,学习node的时候,我们往往会看到这个模块被大量运用。

  • path模块提供了用于处理文件和目录路径的使用工具

utils.js

我们可以到其中去看一下代码,其实光从名字上我们可以推断出,它可能是为整个脚手架提供方法的。我们可以先来看一下头部引用的资源文件:

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

同样的,它也引用了path模块和config目录中的index.js文件,之后的话是一个npm包——extract-text-webpack-plugin。这个包是用来分离css和js的内容的。后续我们可以详细了解一下。同时,它还引用的package.json文件,这是一个json文件,加载过来之后,会变成一个对象。

所以,我们需要从它的头部依赖开始说起:
我们可以来分析一下config目录下的index.js文件。
index.js

这个文件中,其实有十分充足的代码注释,我们也可以来深入探究一下。

从代码中,我们可以看到通过module.exports导出了一个对象,其中包含两个设置dev和build。

在dev中,设置了一些配置,代码如下:

'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require('path')

module.exports = {
  dev: {

    // 路径
    assetsSubDirectory: 'static',  // 静态资源路径
    assetsPublicPath: '/',  // 公共资源路径
    proxyTable: {}, // 代理表

    // 各种开发服务器设置
    host: '0.0.0.0', // 可被 process.env.HOST 覆盖
    port: 8081, // 可被 process.env.HOST 覆盖,如果正在使用端口,将确定一个空闲端口
    autoOpenBrowser: false, // 自动打开浏览器
    errorOverlay: true, // 错误叠加
    notifyOnErrors: true, // 通知上的错误
    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-

    // 使用 eslint 加载程序?  如果为true 则在捆绑过程中删除您的代码,并删除错误 并警告显示在控制台中
    useEslint: true,
    // 如果为true 则在浏览器的错误叠加窗口中还将显示错误和警告
    showEslintErrorsInOverlay: false,
    
    /**
     * Source Maps // 源地图
     */

    // https://webpack.js.org/configuration/devtool/#development
    devtool: 'cheap-module-eval-source-map',  // 开发工具 抛出错误在哪一行

    // 如果你在devtool中调试 vue 文件时遇到问题
    // 将此设置为false-可能会有帮助
    // https://vue-loader.vuejs.org/en/options.html#cachebusting
    cacheBusting: true, // 缓存破坏
	// 根据CSS Loader(卸载)自诉文件,默认情况下,CSS Sourcemaps(资源映射)处于关闭状态,因为相对路径在此选项中处于"沼泽"状态
     // (https://github.com/webpack/css-loader#sourcemaps)
     // 根据我们经验,它们通常会按预期运行
     // 仅在启用此选项时注意此问题
    cssSourceMap: true // css源图
  }
}

通过它的注释,我们可以理解它在dev 中配置了静态路径、本地服务器配置项、Eslint、Source Maps等参数。如果我们需要在开发中,改动静态资源文件、服务器端口等设置、可以在这个文件中进行修改。

下面还有一个build的对象,它是在vue本地服务器启动时,打包的一些配置,代码如下:

build: {
    // index.html 模板
    index: path.resolve(__dirname, '../dist/index.html'),

    // 路径
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',  

    /**
     * 原地图
     */
 
    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // 默认关闭Gzip,因为许多流行的静态主机(例如Surge或Metlify)已经为您静态压缩了所有静态资产
    // 在设置为 true 之前 请确保:npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // 生成完成后,运行带有附加参数的build命令以查看捆绑分析器报告:`npm run build --report`
    // 设置为true 或 false始终将其打开或关闭
    bundleAnalyzerReport: process.env.npm_config_report
  }

其中包括模板文件的修改,打包完目录之后的一些路径设置,gzip压缩等。明白了这些字段的意思之后,就可以在之后的开发中,主动根据项目需求,改动目录内容。

聊完config下的index.js文件,回到utils.js文件中,我们可以来看几个其中的方法,来分析他们分别起到了什么作用。

  1. assetsPath方法
    接受一个_path参数
    返回static(静态)目录位置拼接的路径。
    它根据nodejs的proccess.env.NODE_ENV变量,来判断当前运行的环境。返回不同环境下面的不同static目录位置拼接给定的_path参数。

  2. cssLoaders方法
    接受一个options参数,参数还有的属性:sourceMap、usePostCSS。
    同时,这里用到了我们之前提到的extract-text-webpack-plugin插件,来分离出js中的css代码,然后分别进行打包。同时,它返回一个对象,其中包含了css预编译器(less、sass、stylus)loader生成方法等。如果你的文档明确只需要一门css语言,那么可以稍微清楚一些语言,同时可以减少npm包的大小(毕竟这是一个令人烦躁的东西)。

  3. styleLoaders方法
    接受的options对象和上面的方法一致。该方法只是根据cssLoaders中的方法配置,生成不同loaders。然后将其返回。

  4. createNotifierCallback方法
    此处调用了一个模块,可以在GitHub上找到,它是一个原生的操作系统上发送通知的nodeJS模块。用于返回脚手架错误的函数

一共这么四个函数方法,在utils中被定义到。

回看到webpack.base.conf.js文件中,我们可以直接跳过config目录下的index.js文件,之前已经分析过了。直接来看一下vue-loader.conf.js下的内容。

vue-loader.conf.js

这个文件中的代码非常的少,我们可以直接贴上代码,然后来分析,其中的作用。代码如下:

'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
  ? config.build.productionSourceMap
  : config.dev.cssSourceMap

module.exports = {
  loaders: utils.cssLoaders({
    sourceMap: sourceMapEnabled,
    extract: isProduction
  }),
  cssSourceMap: sourceMapEnabled,
  cacheBusting: config.dev.cacheBusting,
  transformToRequire: {
    video: ['src', 'poster'],
    source: 'src',
    img: 'src',
    image: 'xlink:href'
  }
}

其中,主要就是根据NODE_ENV这个变量,然后分析是否是生产环境,然后将根据不同的环境来加载,不同的环境,来判断是否开启了sourceMap(编译后代码对源码的映射)的功能。方便之后在cssLoaders中加上sourceMap功能。然后判断是否设置了cacheBusting属性,它指的是缓存破坏,特别是进行sourceMap debug时,设置成false是非常有帮助的。最后就是一个转化请求的内容,video、source、img、image等的属性进行配置。

具体的还是需要去了解vue-loader这个webpack的loader加载器。

分析了这么多,最终回到webpack.base.conf.js文件中

webpack.base.conf.js

其实这两个方法,其中一个是来合并path路径的,另一个是加载Eslint的rules的。

我们直接看后面那个函数,createLintingRule方法:

其中,加载了一个formatter,这个可以在终端中显示eslint的规则错误,方便开发者直接找到相应的位置,然后修改代码。

之后的一个对象,就是webpack的基础配置信息。我们可以逐一字段进行分析:

  • context => 运行环境的上下文,就是实际的目录
  • entry => 入口文件:src下的main.js文件
  • output => 输出内容,这内部的配置会根据不同的运行环境来进行变化
  • resolve => 其中的extensions字段,指定检测的文件后缀,同时alias是用于指定别名的。在引用文件路径中,如果有别名的符号,会被替换成指定的路径。
  • module => 配置了一些eslint、vue、js、图片资源、字体图标、文件等加载的loader。详细的可以去看webpack的官方网站。
  • node => 此处部分有注释,主要是阻止一些webpack的默认注入行为,因为在vue中,已经具备了这些功能。

看完这些,你或许对webapck.base.conf.js中的内容有了一些初步的了解。其实,看懂它还需要你了解webpack这个非常有用的打包工具。

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}



module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  node: {
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native).
    setImmediate: false,
    // prevent webpack from injecting mocks to Node native modules
    // that does not make sense for the client
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}

之后,我们在来回看webpack.dev.conf.js这个文件

webpack.dev.conf.js

这个文件中,引用了webapck-merge这npm包,它可以将两个配置对象,进行合并。代码如下:

const merge = require('webpack-merge');
const devWebpackConfig = merge(baseWebpackConfig, {
    ...
}

这样就合并了base中的webpack配置项。之后,我们可以来看一下dev环境中的新增了那些配置项,它们分别起到了什么作用?

  1. 首先,在module的rules中增加了cssSourceMap的功能
  2. 然后就是devtools,通过注释的英文翻译,可以知道cheap-module-eval-source-map使得开发更快。
  3. 之后,就是devSever的一些配置项了。其中包块客户端报错级别、端口、host等等
  4. 还有新增的plugins,我们可以来看一下实际新增的plugins(具体可以看webpack文档):
  • 定义process.env
  • HotModuleReplacementPlugin: 模块热替换插件
  • NameModulesPlugin: 显示模块加载相对路径插件
  • NoEmitOnErrorsPlugin: 在编译出现错误时,使用 NoEmitOnErrorsPlugin 来跳过输出阶段。这样可以确保输出资源不会包含错误
    HtmlWebpackPlugin: 使用插件生成一个指定的模版。

之后,还有一个函数,确保启动程序时,如果端口被占用时,会通过portfinder来发布新的端口,然后输出运行的host字符串。

webpack.prod.conf.js

这是打包到生产环境中,会被用到的文件。我们可以看到,它相对于之前的webapck.dev.conf.js文件少了一些插件,多了更多的插件。我们也可以和之前一样,通过它新增的一些东西,来知道它到底干了什么!(此处的新增是相对于webpack.dev.conf.js没有的内容)

  1. 新增了output的配置,我们可以看到它在output中新增了一些属性,将js打包成不同的块chunk,然后使用hash尾缀进行命名
    2 添加了一些插件:
  • UglifJsPlugin: 这个是用来丑化js代码的
  • ExtractTextplugin: 这里新增了一些属性,在打包的css文件也增加了块和hash尾缀
  • OptimizeCssplugin: 这里是来优化css文件的,主要就是压缩css代码
  • HashedModuleIdsPlugin: 保证module的id值稳定
  • optimize: 这里是webpack一系列优化的措施,具体可以逐一查看官方文档
  • CopyWebPlugins: 自定义assets文件目录
  1. 如果没有进行gzip压缩,调用CompressionWebpackPlugin插件进行压缩
    这样,我们的webpack配置文件内容基本上就全部看完了。或许,会有点蒙,还是看官方文档来的实在。

最后,还需要分析一个build.js文件。

build.js

这个文件是在打包的时候,会被用到的。

首先,文件的开头请求了check-version.js中的函数,然后确定了一下node和npm的版本。相对于较低版本的node和npm,在打包过程中,会产生警告。之后,设置环境参数,设置成生产环境,之后就是一系列打包的流程。

原文 :https://segmentfault.com/a/1190000012581869?utm_source=tag-newest

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值