Vue-cli有两个文件——buildconfig:build文件包含了脚手架在开发环境和生产环境下webpack该如何配置。config文件则包含了build文件下webpack具体配置的值。换句话说,build下的webpack配置的值要引入config后才能获取到。

一.config文件夹下一共有三个文件:

1.dev.env.js: 导出开发环境名称;

2.prod.env.js: 导出生产环境名称;

3.index.js: 导出不同环境的具体配置;

二.build文件夹下一共有七个文件:

1.build.js: 编译时的入口文件,当执行npm run build时其实就是执行node build/build.js(在package.json中);

2.check-versions.js: 编译代码时执行的确认node和npm版本的文件,如果版本不符,则停止编译;

3.utils.js:这个文件有两个作用,一是作为vue-loader的配置来使用;另一个是用来给开发环境和生产环境配置loader;

4.vue-loader.conf.js:vue-loader的配置,用在webpack.base.conf.js中;

5.webpack.base.conf.js:vue-cli脚手架的基础webpack配置,通过与webpack.dev.conf.js和webpack.prod.conf.js两个配置文件的合并(合并方式我会在下一章来讲)来实现“不重复原则(Don't repeat yourself - DRY),不会在不同的环境中配置相同的代码”。

6.webpack.dev.conf.js:开发环境下的webpack的配置;

7.webpack.prod.conf.js:生产环境下的webpack的配置;

三.config文件

1.prod.env.js:

//导出一个对象,对象有一个当前node环境的属性,值为“production”(生产环境)

module.exports = { NODE_ENV: '"production"'}

2.dev.env.js:

//导出另一个对象,属性为当前的node环境,值为“development”(开发环境)

const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, { NODE_ENV: '"development"'})

    • 这里要着重说一下webpack-merge这个包,这个包的作用是来合并两个配置文件对象并生成一个新的配置文件,有点儿类似于es6的Object.assign()方法。如果合并的过程中遇到冲突的属性,第二个参数的属性值会覆盖第一个参数的属性值。
    • 前面写到webpack.base.conf.js与webpack.dev.conf.js和webpack.prod.conf.js的合并也用到了webpack-merge。Vue-cli将一些通用的配置抽出来放在一个文件内(webpack.base.conf.js),在对不同的环境配置不同的代码,最后使用webpack-merge来进行合并,减少重复代码。

3.index.js:
index.js作为具体的配置值,我觉得没必要把代码贴出来了,大家可以拿上面的的脑图或者自己项目里的文件来结合我后面要说的代码来看。

四.build文件

1.check.versions.js:

//chalk 是一个用来在命令行输出不同颜色文字的包,可以使用chalk.yellow("想添加颜色的文字....")
//来实现改变文字颜色的;
const chalk = require('chalk') //semver 的是一个语义化版本文件的npm包,其实它就是用来控制版本的;
const semver = require('semver')const packageConfig = require('../package.json') //一个用来执行unix命令的包
const shell = require('shelljs') //child_process 是Node.js提供了衍生子进程功能的模块,execSync()方法同步执行一个cmd命令,
//将返回值的调用toString和trim方法
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
} const versionRequirements = [
{ name: 'node', //semver.clean()方法返回一个标准的版本号,切去掉两边的空格,比如semver.clean(" =v1.2.3 ")
//返回"1.2.3",此外semver还有vaild,satisfies,gt,lt等方法,
//这里查看https://npm.taobao.org/package/semver可以看到更多关于semver方法的内容
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
//shell.which方法是去环境变量搜索有没有参数这个命令
if (shell.which('npm')) {
versionRequirements.push({
name: 'npm',
//执行"npm --version"命令
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
}
)} //后面这部分代码就比较好理解了
module.exports = function () { const warnings = []
for (let i = 0; i < versionRequirements.length; i++) {
   const 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 (let i = 0; i < warnings.length; i++) { const warning = warnings[i] console.log(' ' + warning) }
console.log() process.exit(1) }}

2.utils.js:

const path = require('path')const config = require('../config')
//这个plugin的作用是将打包后生成的css文件通过link的方式引入到html中,如果不适用这个插件css代码会
//放到head标签的style中
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')
//process.env.NODE_ENV是一个环境变量,它是由webpack.dev/prod.conf.js这两个文件声明的;
//这里的意思是判断当前是否是开发环境,如果是就把config下index.js文件中build.assetsSubDirectory或
//dev.assetsSubDirectory的值赋给assetsSubDirectory
exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
//path.posix.join是path.join的一种兼容性写法,它的作用是路径的拼接,这里返回的是"static/_path"
return path.posix.join(assetsSubDirectory, _path
)}
//cssLoaders的作用是导出一个供vue-loader的options使用的一个配置;
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
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
})
})
}
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
} // styleLoaders是用来给webpack提供所有和css相关的loader的配置,它也使用了cssLoaders()方法;
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
} //'node-notifier'是一个跨平台系统通知的页面,当遇到错误时,它能用系统原生的推送方式给你推送信息
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')
})
}
}
  • cssLoaders方法根据传进来的参数(options)是否有extract属性来返回不同的值,如果你看了后面的代码你就会知道在生产模式下extract属性为true,开发模式下为false。也就是说,在生产模式下返回的是一个类似于这样的数组:

ExtractTextPlugin.extract({
use: ["css-loader","less-loader","sass-loader"...],
fallback: 'vue-style-loader'
})

这些css代码打包以link的方式放到HTML中。当然了,use的值确切的说应该是这样:

[ { loader: 'css-loader', options: { sourceMap: true } }, { loader: 'less-loader', options: { sourceMap: true } } ]
我为了方便看就简写了。

而在开发模式下,cssLoaders返回的是:

["vue-style-loader","css-loader","less-loader","sass-loader"...] //我还是简写了

styleLoaders方法返回的值就简单了,它返回的就是webpack中module里常用的配置格式:

[
   {
      test: /\.css$/,
      use: [ 'style-loader', 'css-loader' ]
    },
...
]

3.vue-loader.conf.js:

const utils = require('./utils')
const config = require('../config') //不同环境为isProduction 赋值: 生产环境为true,开发环境为false
const isProduction = process.env.NODE_ENV === 'production' //不同环境为sourceMapEnabled 赋值: 这里都为true
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
//导出vue-loader的配置,这里我们用了utils文件中的cssLoaders();
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting, //transformToRequire的作用是在模板编译的过程中,编译器可以将某些属性,如src转换为require调用;
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}

4.webpack.base.conf.js:

const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf') //resolve这个函数返回的是当前目录下"../dir"这个文件夹,__dirname指的是当前文件所在路径
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: {
//自动解析扩展,比如引入对应的文件,js,vue,json的后缀名就可以省略了
extensions: ['.js', '.vue', '.json'],
alias: {
//精准匹配,使用vue来替代vue/dist/vue.esm.js
'vue$': 'vue/dist/vue.esm.js',
//使用@替代src路径,当你引入src下的文件是可以使用import XXfrom "@/xx"
'@': resolve('src'),
}
}, //一些loader配置,避免篇幅过长我省略一部分,大家可以看自己的文件
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')]
},
......
]
}, //node里的这些选项是都是Node.js全局变量和模块,这里主要是防止webpack注入一些Node.js的东西到vue中
node: {
setImmediate: false,
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}

5.webpack.dev.conf.js:

const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf') //一个负责拷贝资源的插件
const CopyWebpackPlugin = require('copy-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') //一个更友好的展示webpack错误提示的插件
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') //一个自动检索端口的包
const portfinder = require('portfinder') const HOST = process.env.HOSTconst PORT = process.env.PORT && Number(process.env.PORT) const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.dev.cssSourceMap,
usePostCSS: true
})
}, devtool: config.dev.devtool,
// devServer的配置大家看文档就好了
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false,
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true,
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [ //还记得之前说的生产环境和开发环境的变量在哪儿定义的吗?对,就是这里
new webpack.DefinePlugin({
process.env: require('../config/dev.env')
}), //模块热替换的插件,修改模块不需要刷新页面
new webpack.HotModuleReplacementPlugin(), //当使用HotModuleReplacementPlugin时,这个插件会显示模块正确的相对路径
new webpack.NamedModulesPlugin(), //在编译出错时,使用NoEmitOnErrorsPlugin来跳过输出阶段,这样可以确保输出资源不会包含错误
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}), // 将static文件夹和里面的内容拷贝到开发模式下的路径,比如static下有个img文件夹,里面有张图片
// 我们可以这样访问:localhost:8080/static/img/logo.png
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
}) //这里主要是做端口的检索以及npm run dev后对错误的处理,我们可以看这里使用了前面引入的
//'friendly-errors-webpack-plugin'插件
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
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)
}
})
})

关于devServer有两点要说明一下:

  • contentBase是来告诉服务器在哪里提供静态的内容,这里我们使用false的原因是使用了“copy-webpack-plugin”插件,不需要使用contentBase了;
  • quiet开启后(true),除了初始启动信息之外的任何内容都不会被打印到控制台,即使是webpack 的错误或警告在控制台也不可见。不过我们用了'friendly-errors-webpack-plugin'插件,就可以设为true了。

6.webpack.prod.conf.js 

经过前面这么多代码的分析,其实webpack.prod.conf.js的配置已经很简单了,大致跟webpack.dev.conf.js的配置方式差不多,就是多了几个plugins:

  • UglifyJsPlugin是用来压缩JS代码
  • optimize-css-assets-webpack-plugin是用来压缩css代码
  • HashedModuleIdsPlugin会根据模块的相对路径生成一个四位数的hash作为模块id
  • ModuleConcatenationPlugin可以预编译所有模块到一个包中,加快浏览器的运行速度
  • CommonsChunkPlugin拆分公共模块,vue里拆分了vendor,manifest和app三个模块
  • compression-webpack-plugin gzip压缩
  • webpack-bundle-analyzer可以查看打包的具体情况,比如打了多少个包,每个包多大等

好了,plugins的介绍到此结束,接下来就是最后一个文件,也是npm run build编译时的入口文件——build.js了。

同样的,build.js文件其实也没什么可说的了,无非就是执行webpack.prod.conf.js文件,遇到错误时在命令行提示。需要注意的是,build.js里引入了“rimraf”的包,它的作用是每次编译时清空dist文件,避免多次编译时造成文件夹的重复和混乱。

Vue-cli的配置知识的更多相关文章

  1. @vue/cli的配置知道多少-publicPath,outputDir,assetsDir,indexPath,filenameHashing,configureWebpack,productionSourceMap

    vue.config.js的简单介绍 vue.config.js 是一个可选的配置文件, 在项目的 (和 package.json 同级的) 根目录中存在这个文件. 默认情况没有这个文件需要我们手动去 ...

  2. [Vue CLI 3] 配置解析之 parallel

    官方文档中介绍过在 vue.config.js 文件中可以配置 parallel,作用如下: 是否为 Babel 或 TypeScript 使用 thread-loader. 该选项在系统的 CPU ...

  3. [Vue CLI 3] 配置解析之 indexPath

    在 vue.config.js 配置中有一个 indexPath 的配置,我们先看看它有什么用? 用来指定 index.html 最终生成的路径(相对于 outputDir) 先看看它的默认值:在文件 ...

  4. Vue CLI 3 配置兼容IE10

    最近做了一个基于Vue的项目,需要兼容IE浏览器,目前实现了打包后可以在IE10以上运行,但是还不支持在运行时兼容IE10及以上. 安装依赖 yarn add --dev @babel/polyfil ...

  5. [Vue CLI 3] 配置 webpack-bundle-analyzer 插件

    首先还是简单介绍一下 webpack-bundle-analyzer 是做什么的: Visualize size of webpack output files with an interactive ...

  6. [Vue CLI 3] 配置解析之 css.extract

    大家还记得我们在老版本中,对于线上环境配置中会把所有的 css 多打成一个文件: 核心是使用了插件 extract-text-webpack-plugin,方式如下: 第一步都是加载插件 const ...

  7. Vue CLI 3.0脚手架如何在本地配置mock数据

    前后端分离的开发模式已经是目前前端的主流模式,至于为什么会前后端分离的开发我们就不做过多的阐述,既然是前后端分离的模式开发肯定是离不开前端的数据模拟阶段. 我们在开发的过程中,由于后台接口的没有完成或 ...

  8. vue cli 3 lintOnSave 配置有时无效问题

    一个使用vue cli 3.2创建的项目,创建时未开启 lintOnSave,后来希望开启并设置为 lintOnSave: 'error',但配置不生效. 解决方法1:新创建项目(此时vue cli ...

  9. 使用 vue-cli-service inspect 来查看一个 Vue CLI 3 项目的 webpack 配置信息(包括:development、production)

    使用 vue-cli-service inspect 来查看一个 Vue CLI 3 项目的 webpack 配置信息(包括:development.production) --mode 指定环境模式 ...

  10. @vue/cli 3.x项目脚手架 webpack 配置

    @vue/cli  是一个基于 Vue.js 进行快速开发的完整系统. @vue/cli   基于node服务  需要8.9以上版本 可以使用 nvm等工具来控制node版本  构建于 webpack ...

随机推荐

  1. Android BLE与终端通信(五)——Google API BLE4.0低功耗蓝牙文档解读之案例初探

    Android BLE与终端通信(五)--Google API BLE4.0低功耗蓝牙文档解读之案例初探 算下来很久没有写BLE的博文了,上家的技术都快忘记了,所以赶紧读了一遍Google的API顺便 ...

  2. TCP/IP滑动窗口

    T C P使用一种窗口(w i n d o w)机制来控制数据流.当一个连接建立时,连接的每一端分配一个缓冲区来保存输入的数据,并将缓冲区的尺寸发送给另一端.当数据到达时,接收方发送确认,其中包含了自 ...

  3. Unity 5.X扩展编辑器之打包assetbundle

    5.x的assetbundle与4.x以及之前的版本有些不同,不过本质是一样的,只不过5.x打包assetbundle更为简单和人性化了,总体来说只需要三个步骤: 第一步:创建打包资源 //这里是一个 ...

  4. leetcode【67】-Bulb Switcher

    题目描述: There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off ...

  5. 《java入门第一季》之面向对象(代码块一网打尽)

    上一篇里面对代码块做出介绍,这里给出一个面试题,加深印象. 如有毁三观的地方,请见谅.拒绝黄赌毒 写程序的执行结果. class Student { static { System.out.print ...

  6. The type java.lang.Object cannot be resolved. It is indirectly referenced from required .class files

    The type java.lang.Object cannot be resolved.It is indirectly referenced from required .class files ...

  7. PS 图像调整算法— —渐变映射

    这个调整简单来说就是先建立一张lookup table, 然后以图像的灰度值作为索引,映射得到相应的颜色值.图像的灰度值是由图像本身决定的,但是lookup table 却可以各种各样,所以不同的lo ...

  8. 面试之路(6)-BAT面试之操作系统内存详解

    本文主要参考两篇博客,读后整理出来,以供大家阅读,链接如下: http://blog.jobbole.com/95499/?hmsr=toutiao.io&utm_medium=toutiao ...

  9. twisted高并发库transport函数处理数据包的些许问题

    还是在学校时间比较多, 能够把时间更多的花在学习上, 尽管工作对人的提升更大, 但是总是没什么时间学习, 而且工作的气氛总是很紧凑, 忙碌, 少了些许激情吧.适应就好了.延续着之前对twisted高并 ...

  10. 自制node.js + npm绿色版

    自制node.js + npm绿色版   Node.js官网有各平台的安装包下载,不想折腾的可以直接下载安装,下面说下windows平台下如何制作绿色版node,以方便迁移. 获取node.exe下载 ...