快速入门vue-cli配置

作为一名使用了一段时间Vue.js的新手,相信和不少初入Vue的朋友一样,都对Vue-cli的配置一知半解。后来通过对webpack的学习,也算是对脚手架的配置有了一定的了解,所以也想把这段时间自己的成果分享给大家,希望能和大家一起进步。

有两点要说明的:

  1. 阅读本文需要了解一点点webpack的知识,至少要entry,output,module,plugins都是做什么,以及一些常用的loader和plugins;
  2. 本文使用的是最新版的vue,配置可能会和大家的有所不同,不过差距不会太大,不影响阅读;

一.起步

先放一张自己整理的简易脑图:

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

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

  • dev.env.js: 导出开发环境名称;
  • prod.env.js: 导出生产环境名称;
  • index.js: 导出不同环境的具体配置;

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

  • build.js: 编译时的入口文件,当执行npm run build时其实就是执行node build/build.js(在package.json中);
  • check-versions.js: 编译代码时执行的确认node和npm版本的文件,如果版本不符,则停止编译;
  • utils.js:这个文件有两个作用,一是作为vue-loader的配置来使用;另一个是用来给开发环境和生产环境配置loader;
  • vue-loader.conf.js:vue-loader的配置,用在webpack.base.conf.js中;
  • webpack.base.conf.js:vue-cli脚手架的基础webpack配置,通过与webpack.dev.conf.js和webpack.prod.conf.js两个配置文件的合并(合并方式我会在下一章来讲)来实现“不重复原则(Don‘t repeat yourself - DRY),不会在不同的环境中配置相同的代码”
  • webpack.dev.conf.js:开发环境下的webpack的配置;
  • 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来进行合并,减少重复代码。

关于更多webpack-merge请点击https://www.npmjs.com/package/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()和styleLoaders()这两个方法返回的是个什么东西,我在这里简单的写一下:

  • 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配置的分析基本结束了,相信了解webpack的朋友看起来一定非常简单,配置主要麻烦的地方在于低耦合导致经常需要来回翻文件才能看懂配置,如果大家结合着文章开头的脑图看可能会相对容易些。

一个坏消息是这个文章发布的时候webpack4.0已经上线了,Vue-cli新版也进入了Beta测试阶段,所以这篇文章大家看看就好,了解一下思路,马上配置又会更新的......

原文地址:https://www.cnblogs.com/caideyipi/p/8496656.html

时间: 2024-10-29 20:40:37

快速入门vue-cli配置的相关文章

Vue -- ES6 快速入门,Vue初识

一.ES6快速入门 let和const let ES6新增了let命令,用于声明变量.其用法类似var,但是声明的变量只在let命令所在的代码块内有效. { let x = 10; var y = 20; } x // ReferenceError: x is not defined y // 20 效果如下: var声明变量存在变量提升.也就是在声明变量之前就可以使用该变量. console.log(x) // undefined,var声明变量之前可以使用该变量 var x = 10; 刷新

Android开发快速入门(环境配置)

Android是一种激动人心的开源移动平台,它像手机一样无处不在,得到了Google以及其他一些开放手机联盟成员(如三星.HTC.中国移动.Verizon和AT&T等)的支持,因而不能不加以学习,否则你承担不起为此付出的代价. 好在Android开发入门很容易,即使没有Android手机都没关系,只需有一台可供安装Android SDK和设备模拟器的计算机即可. 本章首先介绍如何安装所有的开发工具,然后再创建一个可运行的应用——Android版“Hello, World”.如果你并非Androi

程序员带你学习安卓开发,十天快速入门-开发工具配置学习

上次课程:.Net程序员学习Android开发-第一课 讲到,.Net程序员学习Android开发的必要性以及对安卓大环境的相关介绍. 其中看到有网友评论,称,搞C#的去搞安卓,还怪自己的移动平台不给力.有的人说,学习.Net就学.Net学习什么安卓.这时的我首先想到了,固步自封的大清朝.当然并不是对这部分人排斥.只能说是想法不一致,认知略有不同,也没有错与对,我只是想把我自己的想法表达出来,期望与您产生共鸣.的确迄今为止,我仍然认为C#是当今我见过的最好的语言.设计规范语法总使我赶到兴奋其优美

快速入门Vue.js

了解一门编程语言,Hello World是我们的罗马之路. 这段代码在画面上输出"Hello World!". <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <!--这是我们的View--> <div id="app&quo

快速入门Vue

前端技术发展很快,近日一个项目中想用Vue框架,对此对Vue基础进行了一些学习整理 何为Vue,官网 解释Vue.js(读音 /vju?/,类似于 view) 是一套构建用户界面的渐进式框架 这里记录主要是关于Vue中基础渲染DOM的一些操作 <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <!-- moblile use --> <meta name="

Hadoop快速入门01——基本配置

原文地址:https://www.cnblogs.com/mubeier/p/9703022.html

vue.js--60分钟快速入门

Vue.js--60分钟快速入门 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的API,使得我们能够快速地上手并使用Vue.js. 本文摘自:http://www.cnblogs.com/keepfool/p/5619070.html 如果你之前已经习惯了用jQuery操作DOM,学习Vue.js时请先抛开手动操作DOM的思维,因为Vue.js是数据驱动的,你无需手动操作DOM

程序员带你学习安卓开发,十天快速入门-基础知识(四)

关注今日头条-做全栈攻城狮,学代码也要读书,爱全栈,更爱生活.提供程序员技术及生活指导干货. 如果你真想学习,请评论学过的每篇文章,记录学习的痕迹. 请把所有教程文章中所提及的代码,最少敲写三遍,达到熟悉的效果. 本系列课程是.Net程序员学习安卓开发系列课程. 下面是前三次课程列表: 程序员带你学习安卓开发,十天快速入门-安卓学习必要性 程序员带你学习安卓开发,十天快速入门-开发工具配置学习 程序员带你学习安卓开发,十天快速入-对比C#学习java语法 为了大家系统有效的快速入门安卓开发,推荐

DB2 Connect 服务器快速入门pdf

下载地址:网盘下载 DB2 Connect 服务器快速入门 安装和配置DB2 Connect服务器9.7 安装和配置DB2 connect 服务器提供准备及安装db2 connect服务器产品所需的所有信息.其中包括特定于每个受支持的操作系统的信息.还讲述了db2 connet服务器与受支持的数据服务器产品之间的关系,包括如何配置连接.

vue.js的快速入门使用

1. vue.js的快速入门使用 1.1 vue.js库的下载 vue.js是目前前端web开发最流行的工具库,由尤雨溪在2014年2月发布的. 另外几个常见的工具库:react.js /angular.js 官方网站: ? 中文:https://cn.vuejs.org/ ? 英文:https://vuejs.org/ 官方文档:https://cn.vuejs.org/v2/guide/ vue.js目前有1.x.2.x和3.x 版本,我们学习2.x版本的. 1.2 vue.js库的基本使用