转载自 vue-cli2、vue-cli3脚手架详细讲解

前言:

vue脚手架指的是vue-cli它是vue官方提供的一个快速构建单页面(SPA)环境配置的工具,cli 就是(command-line-interface  ) 命令行界面 。vue-cli是基于node环境利用webpack对文件进行编译、打包、压缩、es6转es5等一系列操作。目前vue-cli已经升级到了3.0版本,3.0所需的webpack版本是4.xxx,2.0版本目前也很流行,2.0所需的webpack版本是3.xxx,我们来讲讲两者的配置:

(1)Vue2.0

一.安装node.js环境:

    去node官网下载node.js并安装(http://nodejs.cn/download/)。安装完成后可以在终端执行 node -v查看node 是否安装成功,下图是安装成功的提示,显示出当前安装的node的版本号。

二.全局安装webpack

    为了在其他任何目录下都能使用到webpack,进行全局安装,执行npm install webpack@3.12.0 -g 命令,npm 是Node集成的工具 npm install 是从github上下载webpack最新的包,“@3.12.0”表示安装指定的版本,因为现在已经升级到了4.0版本,如果不指定版本版本号就会安装最新的版本,同时vue-cli2需要的是3.xxx的版本,所以我们指定了一个固定版本,如果不指定则不需要,"-g" 全称是 " global (全局) "  表示全局安装。检查是否安装成功终端执行“webpack -v”或者"webpack --version",如果显示具体的版本号则表示安装成功。

 三.全局安装 vue-cli2

执行“npm install  @vue/cli  -g”命令进行安装。

“npm install  @vue/cli  -g” 命令是脚手架3的,“npm install vue-cli -g”命令才是脚手架2的,脚手架2和脚手架3是不相同的。如果现在使用 “npm install vue-cli -g”命令进行安装的话,下次使用脚手架3的时候就得卸载脚手架2。安装脚手架3,为了减少不必要的操作我们执行 “npm install  @vue/cli  -g ” 命令进行安装,然后再执行 “npm install @vue-cli-init -g ” 将脚手架2下载下来,在此环境下既可以安装脚手架2的模板,有可以安装脚手架3的模板。  检查是否安装成功终端执行“vue -V”或者"vue --version",如果显示具体的版本号则表示安装成功。具体安装方式查看官网(https://cli.vuejs.org/zh/)。

四.初始化项目

  进入到自己要安装项目的文件夹目录,我这里是 “D:\webpackProject\vue-cli2> ”  执行 “vue  init  webpack  vue-cli2-project ” 命令,出现如下图提示 ,“vue-cli2-project” 是我们的项目文件夹的名字,就是最终显示在index.html中的title标签里和package.json中的,也可以自己进行修改,我们一般不会去改,直接按回车键进行下一步。

  “? Project description (A Vue.js project)”  是项目的描述,自己可以修改或者使用默认的,我们一般使用默认的直接按回车键进行下一步,

这里是作者的信息,我们使用默认的,直接下一步,

这里有两个选项:Runtime +  Compiler 和Runtime-only ,Runtime-only要比Runtime +  Compiler 轻大约6KB,而且效率要高, 按上下键可以进行选择,默认是第一个,选择好后按回车键进行下一步, 

这一步是询问是否使用vue-router(路由),因为在项目中我们会用到所以这里按Y 键,进行下一步,

这一步是询问是否使用ESLint(语法检查器),ES (ecscript) 即 javascript ,lint 限制的意思,也就是 javascript语法限制器,使得你的语法更加规范,如果你的语法不规范编辑器就会报错,你可能在开发过程中因为一个空格导致语法不规范进而报错(其实你的代码没有问题的),所以对于初学者不建议使用此语法,所以我们选择 n,并进行下一步操作,

这一步是询问是否使用单元测试,这个用的人比较少,所以我们不适用,输入n并进行一下步,

这一步询问是否要进行e2e(端到端测试),是一个自动化测试的框架,这里我们就不使用了,直接输入n,进行下一步:

    

这里询问我们管理项目是用npm 还是yarn ,这里我们使用npm ,直接回车,接下来就是等待安装node_modules。下图表示安装完成:

执行 cd vue-cli2-project 进入到我们的项目目录下,然后执行 npm run dev 命令进行启动我们的项目,下图是我们的项目目录:

五、 项目目录介绍:

     1、build  文件夹:webpack的一些相关配置;

     2、config  文件夹:项目开发环境和生产环境的一些相关配置;

     3、node_modules  文件夹 :这里存放的是安装包,比如webpack、第三方插件库、项目的依赖文件;

     4、src  文件夹:我们将要写的代码放在这里面,打包上线时会进行编译、压缩等操作。

     5、static 文件夹:这里存放的是一些静态文件比如图片、css文件、不需要进行压缩的js文件,打包时这个文件夹将原封不动的放到dist(打包时自动生产的文件夹)文件夹下面。

     6、.babelrc 文件:ES6语法编译配置,主要是将ES 转成ES 需要适配那些浏览器

     7、.editorconfig 文件:定义代码格式,对代码的风格进行一个统一。

        8、.gitignore 文件:git上传需要忽略的文件格式

     9、  .postcssrc.js 文件:postcss配置文件

10、 index.html  文件:要进行访问的首页面

11、package-lock.json 文件:锁定依赖模块和子模块的版本号

12、package.json 文件:项目基本信息,包依赖信息等

13、README.md  文件:项目说明文件

文件详解:

1、package.json 文件:当我们在命令行时 npm run dev 的时候程序执行的是package.json文件的“script”脚本里的“dev”命令;

这段代码的意思是启动 “webpack-dev-server” 服务器,“--inline” 是 重新加载改变的部分,不会刷新页面,--progress是启动项目时显示进度,“--config build/webpack.dev.conf.js” 是执行build下面的webpack.dev.conf.js配置文件。我们可以添加其他属性比如 “--open” 是启动项目后自动在浏览器打开项目,其它配置可以查看相关文档(https://www.webpackjs.com/configuration/dev-server/#devserver)。“start” 和“dev”的作用是一样的,“build” 的作用是执行 build下的build.js文件,将当前的项目进行打包。打包后生成一个dist文件夹,放在其里面。webpack.dev.conf.js文件是我们在开发环境下的webpack配置文件,打开次文件,内容如下:

2.、build/webpack.dev.conf.js 文件:

'use strict'
const utils = require('./utils')         //引入的工具包
const webpack = require('webpack')      //引入webpack包
const config = require('../config')     //引入 config下的index.js文件
const merge = require('webpack-merge')  //合并配置文件
const path = require('path')            //node的path模块,对路径进行处理
const baseWebpackConfig = require('./webpack.base.conf') //将生产和开发环境下共用的配置文件进行了抽离形成了改文件
const CopyWebpackPlugin = require('copy-webpack-plugin') //拷贝插件
const HtmlWebpackPlugin = require('html-webpack-plugin')  //加载html模块
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') //友好的错误提示插件
const portfinder = require('portfinder')   //在当前机器上找一个可打开的端口号,默认是8080,如果端口号被占用则重新寻找可打开的端口号。const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)const devWebpackConfig = merge(baseWebpackConfig, {   //利用merge插件将 baseWebpackConfig 配置与当前配置进行合并module: {rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })  //引入utils中一些css-loader和postcss-loader},devtool: config.dev.devtool, //控制是否生成以及如何生成源码映射,这里引入的是config下的index.js的 “devtool: 'cheap-module-eval-source-map'”,// these devServer options should be customized in /config/index.js// dev-server的配置devServer: {clientLogLevel: 'warning',      //当使用inline mode,devTools的命令行中将会显示一些调试信息historyApiFallback: {           //当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.htmlrewrites: [{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },],},hot: true,            //启用 webpack 的模块热替换特性contentBase: false,   // since we use CopyWebpackPlugin.compress: true,host: HOST || config.dev.host,   //要开启的域名,可在package.json中的“dev”命令中进行配置port: PORT || config.dev.port,   //要开启的端口号,可在package.json中的“dev”命令中进行配置open: config.dev.autoOpenBrowser,//是否自动在浏览器中打开,可在package.json中的“dev”命令中进行配置overlay: config.dev.errorOverlay? { warnings: false, errors: true }: false,publicPath: config.dev.assetsPublicPath, //proxy: config.dev.proxyTable,   //当出现跨域时设置代理,这里引入了config下的index.js的配置quiet: true, // necessary for FriendlyErrorsPlugin  启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见watchOptions: {poll: config.dev.poll,}},plugins: [ //插件部分new webpack.DefinePlugin({   //配置全局变量'process.env': require('../config/dev.env')  }),new webpack.HotModuleReplacementPlugin(),     // 模块热替换它允许在运行时更新各种模块,而无需进行完全刷新new webpack.NamedModulesPlugin(),            //  HMR shows correct file names in console on update.new webpack.NoEmitOnErrorsPlugin(),          // 这个插件的作用是在热加载时直接返回更新文件名,而不是文件的id。// https://github.com/ampedandwired/html-webpack-pluginnew HtmlWebpackPlugin({   //打包时生成index.html并且自动加载app.js文件  <!-- built files will be auto injected -->filename: 'index.html',template: 'index.html',inject: true}),// copy custom static assetsnew CopyWebpackPlugin([{from: path.resolve(__dirname, '../static'), //将static整个文件夹原封不动地拷贝到dist目录下。to: config.dev.assetsSubDirectory,ignore: ['.*']}])]
})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 testsprocess.env.PORT = port// add port to devServer configdevWebpackConfig.devServer.port = port// Add FriendlyErrorsPlugindevWebpackConfig.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)}})
})

本文件 的核心就是将webpack.base.conf.js的配置(公共配置)与本文件配置进行合并,再看一下 webpack.base.conf.js 文件:

  

3、build/webpack.base.conf.js 文件   

'use strict'
const path = require('path') //node的path模块,对路径进行处理
const utils = require('./utils') //引入的工具包
const config = require('../config')//引入 config下的index.js文件
const vueLoaderConfig = require('./vue-loader.conf') //根据NODE_ENV这个变量分析是否是生产环境,然后根据不同的环境来加载,判断是否开启了sourceMap的功能function resolve (dir) {return path.join(__dirname, '..', dir) //对路径进行处理,获取到绝对路径
}module.exports = {context: path.resolve(__dirname, '../'), //对路径进行处理,跳到当前项目的根目录下entry: {     //入口文件,即项目要引入哪个js文件app: './src/main.js'        //因为 context 中已经跳到了当前项目的根目录下,所以这里的路径是以 ./src 开头},output: { //输出文件,即项目要输出到哪里去path: config.build.assetsRoot,  //输出到根目录下的dist问价夹里,具体地址可以在config下的index.js中进行修改filename: '[name].js',      //以文件的原始名输出publicPath: process.env.NODE_ENV === 'production'   //根据process.env.NODE_ENV 来判断是生产模式还是开发模式,将最终打包的项目要放到服务器的什么地方,默认是 '/' 即服务器的根目录下。? config.build.assetsPublicPath: config.dev.assetsPublicPath},resolve: {extensions: ['.js', '.vue', '.json'],  //简化一些文件名,引入文件时可以不带后缀名alias: {'vue$': 'vue/dist/vue.esm.js','@': resolve('src'),          //简化文件的引入问题,如:本文件中要引入 src下的common里的demo.js,你就可以这样引入:@/common/demo.js}},module: {rules: [// 配置各种loader,来处理对应的文件{test: /\.vue$/,   //使用vue-loader处理以.vue结束的文件loader: 'vue-loader',options: vueLoaderConfig},{test: /\.js$/,    //使用babel-loader处理以.js结束的文件,即js文件loader: 'babel-loader',include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]},{test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,   //使用url-loader处理各种格式的图片资源,最大限制10000KB,这里不处理src同级目录下的static里的图片。loader: 'url-loader',options: {limit: 10000,   name: utils.assetsPath('img/[name].[hash:7].[ext]')  //将处理后的放在img文件下,并且加上7位hash值。}},{test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,   //使用url-loader处理视频文件。loader: 'url-loader',options: {limit: 10000,name: utils.assetsPath('media/[name].[hash:7].[ext]')}},{test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,            //使用url-loader处理字体文件。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 clientdgram: 'empty',fs: 'empty',net: 'empty',tls: 'empty',child_process: 'empty'}
}

  主要的说明已经注释在了文件中,这个问价的主要配置有entry(入口文件)、output(输出文件)、loader ,这些都是必备的,而一些plugins(插件)已经在对应的环境文件(webpack.dev.config.js、webpack.prod.config.js)中进行了配置,再看一下webpack.prod.config.js文件:

 4、build/webpack.prod.config.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')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin') //抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')//主要是用来压缩css文件
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')  //对js文件进行压缩const env = require('../config/prod.env')const webpackConfig = merge(baseWebpackConfig, {module: {rules: utils.styleLoaders({sourceMap: config.build.productionSourceMap,extract: true,usePostCSS: true})},devtool: config.build.productionSourceMap ? config.build.devtool : false,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.htmlnew webpack.DefinePlugin({'process.env': env}),new UglifyJsPlugin({uglifyOptions: {  //配置项compress: {warnings: false}},sourceMap: config.build.productionSourceMap,  //使用sourceMap将错误消息位置映射到模块(这会减慢编译速度)。parallel: true        //启用/禁用多进程并行运行,启用后会提高构建速度}),new ExtractTextPlugin({filename: utils.assetsPath('css/[name].[contenthash].css'),allChunks: true,}),// Compress extracted CSS. We are using this plugin so that possible// duplicated CSS from different components can be deduped.new OptimizeCSSPlugin({cssProcessorOptions: config.build.productionSourceMap? { safe: true, map: { inline: false } }  //判断是否生成内联映射,如果生成则会生成一个source-map文件: { 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-pluginnew HtmlWebpackPlugin({filename: config.build.index, //将会生成一个index.html文件,放到dist文件下template: 'index.html',inject: true,                //将所有js资源放在body标签的底部minify: {                   //控制是否进行压缩removeComments: true,     //删除所有的注释collapseWhitespace: true, //折叠构成文档树中文本节点的空白removeAttributeQuotes: true //尽可能删除属性周围的引号// more options:// https://github.com/kangax/html-minifier#options-quick-reference},// necessary to consistently work with multiple chunks via CommonsChunkPluginchunksSortMode: 'dependency'    //允许控制块在包含到HTML之前按照依赖排序}),// keep module.id stable when vendor modules does not changenew webpack.HashedModuleIdsPlugin(), //该插件会根据模块的相对路径生成一个四位数的hash作为模块id, 建议用于生产环境。// enable scope hoistingnew webpack.optimize.ModuleConcatenationPlugin(),//启用作用域提升,让代码文件更小、运行的更快// split vendor js into its own filenew webpack.optimize.CommonsChunkPlugin({ //主要是用来提取第三方库和公共模块,避免首屏加载的bundle文件或者按需加载的bundle文件体积过大,从而导致加载时间过长name: 'vendor',minChunks (module) {// any required modules inside node_modules are extracted to vendorreturn (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 updatednew 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-chunknew webpack.optimize.CommonsChunkPlugin({name: 'app',async: 'vendor-async',children: true,minChunks: 3}),// copy custom static assetsnew CopyWebpackPlugin([  //复制模块{from: path.resolve(__dirname, '../static'),to: config.build.assetsSubDirectory,ignore: ['.*']}])]
})if (config.build.productionGzip) {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}))
}if (config.build.bundleAnalyzerReport) {const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPluginwebpackConfig.plugins.push(new BundleAnalyzerPlugin())
}module.exports = webpackConfig

当我们执行 npm run build 打包时执行的是: build下的build.js文件,build.js中引入了webpack.prod.config.js,因此build.js才是生产环境所需的webpack文件。

5、build/build.js:

'use strict'
require('./check-versions')() //该文件用于检测node和npm的版本,实现版本依赖process.env.NODE_ENV = 'production'const ora = require('ora')    //在node端加载动画模块
const rm = require('rimraf')  //用来删除文件和文件夹的
const path = require('path')
const chalk = require('chalk') //修改控制台中字符串的样式
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf') const spinner = ora('building for production...') //设置一个动画的内容为 "building for production..."
spinner.start()   //加载动画rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {  //利用 rm 模块先删除dist文件再生成新文件,因为有时候会使用hash来命名,删除整个文件可避免冗余if (err) throw errwebpack(webpackConfig, (err, stats) => {   //将一下配置内容与 webpack.prod.conf.js中的配置进行合并spinner.stop()  //停止动画if (err) throw errprocess.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'))})
})

6、build/check-versions.js:  检测node和npm的版本,实现版本依赖

'use strict'
// 该文件用于检测node和npm的版本,实现版本依赖
const chalk = require('chalk')  //node.js中的模块,作用是修改控制台中字符串的样式
const semver = require('semver')  //node.js中的模块,对版本进行检查
const packageConfig = require('../package.json') //引入page.json文件
const shell = require('shelljs')function exec (cmd) {//通过child_process模块的新建子进程,执行 Unix 系统命令后转成没有空格的字符串return require('child_process').execSync(cmd).toString().trim()
}const versionRequirements = [{name: 'node',currentVersion: semver.clean(process.version),  //使用semver格式化版本versionRequirement: packageConfig.engines.node //获取package.json中设置的node版本}
]if (shell.which('npm')) {versionRequirements.push({name: 'npm',currentVersion: exec('npm --version'),   //自动调用npm --version命令,并且把参数返回给exec函数,从而获取纯净的版本号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)) {//如果上面的版本号不符合package.json文件中指定的版本号,就执行下面错误提示的代码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)}
}

7、build/vue-loader.conf.js:

'use strict'//根据NODE_ENV这个变量分析是否是生产环境,然后根据不同的环境来加载,判断是否开启了sourceMap的功能。方便之后在cssLoaders中加上sourceMap功能。然后判断是否设置了cacheBusting属性,
// 它指的是缓存破坏,特别是进行sourceMap debug时,设置成false是非常有帮助的。最后就是一个转化请求的内容,video、source、img、image等的属性进行配置。具体的还是需要去了解vue-loader这个
// webpack的loader加载器const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction? config.build.productionSourceMap: config.dev.cssSourceMap
//处理项目中的css文件,生产环境和测试环境默认是打开sourceMap,而extract中的提取样式到单独文件只有在生产环境中才需要
module.exports = {loaders: utils.cssLoaders({sourceMap: sourceMapEnabled,extract: isProduction}),cssSourceMap: sourceMapEnabled, cacheBusting: config.dev.cacheBusting,transformToRequire: {//在模版编译过程中,编译器可以将某些属性,如 src 路径,转换为require调用,以便目标资源可以由 webpack 处理.video: ['src', 'poster'],source: 'src',img: 'src',image: 'xlink:href'}
}

8、build/utils:

'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin') 抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象
const packageConfig = require('../package.json')//导出文件的位置,根据环境判断开发环境和生产环境,为config文件中index.js文件中定义的build.assetsSubDirectory或
exports.assetsPath = function (_path) {const assetsSubDirectory = process.env.NODE_ENV === 'production'? config.build.assetsSubDirectory: config.dev.assetsSubDirectoryreturn path.posix.join(assetsSubDirectory, _path)
}//使用了css-loader和postcssLoader,通过options.usePostCSS属性来判断是否使用postcssLoader中压缩等方法
exports.cssLoaders = function (options) {   //导出css-loaderoptions = options || {}const cssLoader = {loader: 'css-loader',options: {sourceMap: options.sourceMap }}const postcssLoader = {loader: 'postcss-loader',options: {sourceMap: options.sourceMap}}// generate loader string to be used with extract text pluginfunction generateLoaders (loader, loaderOptions) {const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] //根据传入的参数判断是使用cssLoader、 postcssLoader还是只使用 cssLoaderif (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) {return ExtractTextPlugin.extract({use: loaders,fallback: 'vue-style-loader'})} else {return ['vue-style-loader'].concat(loaders)}}// https://vue-loader.vuejs.org/en/configurations/extract-css.htmlreturn {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)
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') returnconst 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')})}
}

9、config/index.js: 生产 和 开发 环境下webpack的公共配置文件  

const path = require('path')module.exports = {dev: {  //开发环境下的配置// PathsassetsSubDirectory: 'static', //子目录,一般存放css,js,image等文件assetsPublicPath: '/', //根目录proxyTable: {},  //在这里使用代理解决跨越问题// Various Dev Server settingshost: 'localhost', // 域名port: 8080, // 开启的端口号,默认是8080autoOpenBrowser: true, //是否自动打开浏览器errorOverlay: true,  //浏览器错误提示notifyOnErrors: true, //跨平台错误提示poll: false, // 使用文件系统(file system)获取文件改动的通知devServer.watchOptions/*** Source Maps*/// https://webpack.js.org/configuration/devtool/#developmentdevtool: 'cheap-module-eval-source-map',//增加调试,该属性为原始源代码(仅限行)不可在生产环境中使用cacheBusting: true,//使缓存失效cssSourceMap: true   //代码压缩后进行调bug定位将非常困难,于是引入sourcemap记录压缩前后的位置信息记录,当产生错误时直接定位到未压缩前的位置,将大大的方便我们调试},build: { //生产发环境下的配置// Template for index.htmlindex: path.resolve(__dirname, '../dist/index.html'), //index.html编译后生成的位置和名字// PathsassetsRoot: path.resolve(__dirname, '../dist'),//编译后存放生成环境代码的位置assetsSubDirectory: 'static',  //js,css,images存放文件夹名assetsPublicPath: '/',  //发布的根目录,通常本地打包dist后打开文件会报错,此处修改为./。如果是上线的文件,可根据文件存放位置进行更改路径productionSourceMap: true,devtool: '#source-map',productionGzip: false,productionGzipExtensions: ['js', 'css'],bundleAnalyzerReport: process.env.npm_config_report}
}

10、config/dev.env.js: 

'use strict'
// 当在开发环境下引用(webpack.dev.config.js中的plugin中)的是此文件,次文件指定了 开发模式: node-env ,
//利用merge方法将prod.env.js与本文件进行合并,在开发模式下输出 NODE_ENV="development"//webpack.dev.config.js中的plugin引用如下:// new webpack.DefinePlugin({//   'process.env': require('../config/dev.env')// })
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {NODE_ENV: '"development"'
})

11、config/prod.env.js: 

'use strict'
// 在生产模式下调用此文件
// 在webpack.prod.config.js中的plugin中引用如下://const env = require('../config/prod.env')// new webpack.DefinePlugin({//   'process.env': env// }),
module.exports = {NODE_ENV: '"production"'
}

12 、node_modules文件夹:该文件夹下存放的是node的一些依赖模块,比如:require模块、path模块、http-proxy-middleware模块,还有一些我们通过npm安装的插件模块,比如vue、md5、vue-cli、ivew等。

13.、src文件夹: 该文件夹下面存放的是我们项目代码以及一些文件,components文件夹存放了我们自己写的组件,router文件夹里面存放了路由配置,mian.js是整个项目的入口js,在build文件夹下的webpack.dev.config.js中的entry中有配置(

app: './src/main.js')。App.vue文件是项目的首页面。

vue 3.0

 1.安装vue3:新建一个文件夹,进入该文件夹下,执行 vue create   ( 项目名称) , 如下图:

vuecli3为项目名称,进入下一步,

上面提示:请选择一个配置。下面有3个选项,第一个 “myset  ” 是 我自己手动选择的配置,你们第一个安装你没有这个选项,如果选择了第3个通过手动选择后,下次再安装时会出现在这里,第二个 “default”是默认的,第3个是 手动选择。我们先选择第3个,进入下一步,

这里要我们选择一个配置,按住上下键进行调转,空格键进行选中或者取消,

   

  这一步询问的是 把项目的配置文件放在独立的配置文件中还是放在package.json文件中,这里我们选择第一个,方便我们以后的修改,进行下一步

这里询问的是我们手动配置要不要进行保存,以便下次使用,也就是安装第一步的时候的选择,输入 y,

这里要输入的是要保存的命字,进行一下步安装,

安装完成。

启动项目

                      

这是vue3的项目结构,显然和vue2的结构不一样,没有了config文件夹而且还多了一个.git文件,方便我们项目管理,其中public相当于vue2中的static静态文件夹,相同文件我就不说了,我只说一下不同文件。

我们先看一下package.json文件,

开发依赖少了很多,因为vue3.0讲究的是 0 配置,因为不显示的这些文件不需要我们去改,我们通过npm安装的依赖会存在哪里呢?

这里我安装了2个依赖,很显然是放在package.json文件下的,方便我们去管理自己的依赖。那默认的那些依赖存在哪里呢?

。其实是通过 "@vue/cli-service": "^4.0.0",去管理我们的依赖的,在 “node_modules”  =>  “@vue”  => cli-service => package.json,这里面就是隐藏的依赖。

vue2中的config文件夹隐藏到了“node_modules”  =>  “@vue”  => cli-service => webpack.config.js中,而在webpack.config.js中有这一行代码:

所以再找到Service.js文件,

const fs = require('fs')
const path = require('path')
const debug = require('debug')
const chalk = require('chalk')
const readPkg = require('read-pkg')
const merge = require('webpack-merge')
const Config = require('webpack-chain')
const PluginAPI = require('./PluginAPI')
const dotenv = require('dotenv')
const dotenvExpand = require('dotenv-expand')
const defaultsDeep = require('lodash.defaultsdeep')
const { warn, error, isPlugin, resolvePluginId, loadModule } = require('@vue/cli-shared-utils')const { defaults, validate } = require('./options')module.exports = class Service {constructor (context, { plugins, pkg, inlineOptions, useBuiltIn } = {}) {process.VUE_CLI_SERVICE = thisthis.initialized = falsethis.context = contextthis.inlineOptions = inlineOptionsthis.webpackChainFns = []this.webpackRawConfigFns = []this.devServerConfigFns = []this.commands = {}// Folder containing the target package.json for pluginsthis.pkgContext = context// package.json containing the pluginsthis.pkg = this.resolvePkg(pkg)// If there are inline plugins, they will be used instead of those// found in package.json.// When useBuiltIn === false, built-in plugins are disabled. This is mostly// for testing.this.plugins = this.resolvePlugins(plugins, useBuiltIn)// pluginsToSkip will be populated during run()this.pluginsToSkip = new Set()// resolve the default mode to use for each command// this is provided by plugins as module.exports.defaultModes// so we can get the information without actually applying the plugin.this.modes = this.plugins.reduce((modes, { apply: { defaultModes }}) => {return Object.assign(modes, defaultModes)}, {})}resolvePkg (inlinePkg, context = this.context) {if (inlinePkg) {return inlinePkg} else if (fs.existsSync(path.join(context, 'package.json'))) {const pkg = readPkg.sync({ cwd: context })if (pkg.vuePlugins && pkg.vuePlugins.resolveFrom) {this.pkgContext = path.resolve(context, pkg.vuePlugins.resolveFrom)return this.resolvePkg(null, this.pkgContext)}return pkg} else {return {}}}init (mode = process.env.VUE_CLI_MODE) {if (this.initialized) {return}this.initialized = truethis.mode = mode// load mode .envif (mode) {this.loadEnv(mode)}// load base .envthis.loadEnv()// load user configconst userOptions = this.loadUserOptions()this.projectOptions = defaultsDeep(userOptions, defaults())debug('vue:project-config')(this.projectOptions)// apply plugins.this.plugins.forEach(({ id, apply }) => {if (this.pluginsToSkip.has(id)) returnapply(new PluginAPI(id, this), this.projectOptions)})// apply webpack configs from project config fileif (this.projectOptions.chainWebpack) {this.webpackChainFns.push(this.projectOptions.chainWebpack)}if (this.projectOptions.configureWebpack) {this.webpackRawConfigFns.push(this.projectOptions.configureWebpack)}}loadEnv (mode) {const logger = debug('vue:env')const basePath = path.resolve(this.context, `.env${mode ? `.${mode}` : ``}`)const localPath = `${basePath}.local`const load = envPath => {try {const env = dotenv.config({ path: envPath, debug: process.env.DEBUG })dotenvExpand(env)logger(envPath, env)} catch (err) {// only ignore error if file is not foundif (err.toString().indexOf('ENOENT') < 0) {error(err)}}}load(localPath)load(basePath)// by default, NODE_ENV and BABEL_ENV are set to "development" unless mode// is production or test. However the value in .env files will take higher// priority.if (mode) {// always set NODE_ENV during tests// as that is necessary for tests to not be affected by each otherconst shouldForceDefaultEnv = (process.env.VUE_CLI_TEST &&!process.env.VUE_CLI_TEST_TESTING_ENV)const defaultNodeEnv = (mode === 'production' || mode === 'test')? mode: 'development'if (shouldForceDefaultEnv || process.env.NODE_ENV == null) {process.env.NODE_ENV = defaultNodeEnv}if (shouldForceDefaultEnv || process.env.BABEL_ENV == null) {process.env.BABEL_ENV = defaultNodeEnv}}}setPluginsToSkip (args) {const skipPlugins = args['skip-plugins']const pluginsToSkip = skipPlugins? new Set(skipPlugins.split(',').map(id => resolvePluginId(id))): new Set()this.pluginsToSkip = pluginsToSkip}resolvePlugins (inlinePlugins, useBuiltIn) {const idToPlugin = id => ({id: id.replace(/^.\//, 'built-in:'),apply: require(id)})let pluginsconst builtInPlugins = ['./commands/serve','./commands/build','./commands/inspect','./commands/help',// config plugins are order sensitive'./config/base','./config/css','./config/prod','./config/app'].map(idToPlugin)if (inlinePlugins) {plugins = useBuiltIn !== false? builtInPlugins.concat(inlinePlugins): inlinePlugins} else {const projectPlugins = Object.keys(this.pkg.devDependencies || {}).concat(Object.keys(this.pkg.dependencies || {})).filter(isPlugin).map(id => {if (this.pkg.optionalDependencies &&id in this.pkg.optionalDependencies) {let apply = () => {}try {apply = require(id)} catch (e) {warn(`Optional dependency ${id} is not installed.`)}return { id, apply }} else {return idToPlugin(id)}})plugins = builtInPlugins.concat(projectPlugins)}// Local pluginsif (this.pkg.vuePlugins && this.pkg.vuePlugins.service) {const files = this.pkg.vuePlugins.serviceif (!Array.isArray(files)) {throw new Error(`Invalid type for option 'vuePlugins.service', expected 'array' but got ${typeof files}.`)}plugins = plugins.concat(files.map(file => ({id: `local:${file}`,apply: loadModule(`./${file}`, this.pkgContext)})))}return plugins}async run (name, args = {}, rawArgv = []) {// resolve mode// prioritize inline --mode// fallback to resolved default modes from plugins or development if --watch is definedconst mode = args.mode || (name === 'build' && args.watch ? 'development' : this.modes[name])// --skip-plugins arg may have plugins that should be skipped during init()this.setPluginsToSkip(args)// load env variables, load user config, apply pluginsthis.init(mode)args._ = args._ || []let command = this.commands[name]if (!command && name) {error(`command "${name}" does not exist.`)process.exit(1)}if (!command || args.help || args.h) {command = this.commands.help} else {args._.shift() // remove command itselfrawArgv.shift()}const { fn } = commandreturn fn(args, rawArgv)}resolveChainableWebpackConfig () {const chainableConfig = new Config()// apply chainsthis.webpackChainFns.forEach(fn => fn(chainableConfig))return chainableConfig}resolveWebpackConfig (chainableConfig = this.resolveChainableWebpackConfig()) {if (!this.initialized) {throw new Error('Service must call init() before calling resolveWebpackConfig().')}// get raw configlet config = chainableConfig.toConfig()const original = config// apply raw config fnsthis.webpackRawConfigFns.forEach(fn => {if (typeof fn === 'function') {// function with optional return valueconst res = fn(config)if (res) config = merge(config, res)} else if (fn) {// merge literal valuesconfig = merge(config, fn)}})// #2206 If config is merged by merge-webpack, it discards the __ruleNames// information injected by webpack-chain. Restore the info so that// vue inspect works properly.if (config !== original) {cloneRuleNames(config.module && config.module.rules,original.module && original.module.rules)}// check if the user has manually mutated output.publicPathconst target = process.env.VUE_CLI_BUILD_TARGETif (!process.env.VUE_CLI_TEST &&(target && target !== 'app') &&config.output.publicPath !== this.projectOptions.publicPath) {throw new Error(`Do not modify webpack output.publicPath directly. ` +`Use the "publicPath" option in vue.config.js instead.`)}if (typeof config.entry !== 'function') {let entryFilesif (typeof config.entry === 'string') {entryFiles = [config.entry]} else if (Array.isArray(config.entry)) {entryFiles = config.entry} else {entryFiles = Object.values(config.entry || []).reduce((allEntries, curr) => {return allEntries.concat(curr)}, [])}entryFiles = entryFiles.map(file => path.resolve(this.context, file))process.env.VUE_CLI_ENTRY_FILES = JSON.stringify(entryFiles)}return config}loadUserOptions () {// vue.config.jslet fileConfig, pkgConfig, resolved, resolvedFromconst configPath = (process.env.VUE_CLI_SERVICE_CONFIG_PATH ||path.resolve(this.context, 'vue.config.js'))if (fs.existsSync(configPath)) {try {fileConfig = require(configPath)if (typeof fileConfig === 'function') {fileConfig = fileConfig()}if (!fileConfig || typeof fileConfig !== 'object') {error(`Error loading ${chalk.bold('vue.config.js')}: should export an object or a function that returns object.`)fileConfig = null}} catch (e) {error(`Error loading ${chalk.bold('vue.config.js')}:`)throw e}}// package.vuepkgConfig = this.pkg.vueif (pkgConfig && typeof pkgConfig !== 'object') {error(`Error loading vue-cli config in ${chalk.bold(`package.json`)}: ` +`the "vue" field should be an object.`)pkgConfig = null}if (fileConfig) {if (pkgConfig) {warn(`"vue" field in package.json ignored ` +`due to presence of ${chalk.bold('vue.config.js')}.`)warn(`You should migrate it into ${chalk.bold('vue.config.js')} ` +`and remove it from package.json.`)}resolved = fileConfigresolvedFrom = 'vue.config.js'} else if (pkgConfig) {resolved = pkgConfigresolvedFrom = '"vue" field in package.json'} else {resolved = this.inlineOptions || {}resolvedFrom = 'inline options'}if (resolved.css && typeof resolved.css.modules !== 'undefined') {if (typeof resolved.css.requireModuleExtension !== 'undefined') {warn(`You have set both "css.modules" and "css.requireModuleExtension" in ${chalk.bold('vue.config.js')}, ` +`"css.modules" will be ignored in favor of "css.requireModuleExtension".`)} else {warn(`"css.modules" option in ${chalk.bold('vue.config.js')} ` +`is deprecated now, please use "css.requireModuleExtension" instead.`)resolved.css.requireModuleExtension = !resolved.css.modules}}// normalize some optionsensureSlash(resolved, 'publicPath')if (typeof resolved.publicPath === 'string') {resolved.publicPath = resolved.publicPath.replace(/^\.\//, '')}removeSlash(resolved, 'outputDir')// validate optionsvalidate(resolved, msg => {error(`Invalid options in ${chalk.bold(resolvedFrom)}: ${msg}`)})return resolved}
}function ensureSlash (config, key) {let val = config[key]if (typeof val === 'string') {if (!/^https?:/.test(val)) {val = val.replace(/^([^/.])/, '/$1')}config[key] = val.replace(/([^/])$/, '$1/')}
}function removeSlash (config, key) {if (typeof config[key] === 'string') {config[key] = config[key].replace(/\/$/g, '')}
}function cloneRuleNames (to, from) {if (!to || !from) {return}from.forEach((r, i) => {if (to[i]) {Object.defineProperty(to[i], '__ruleNames', {value: r.__ruleNames})cloneRuleNames(to[i].oneOf, r.oneOf)}})
}

这里面才是我们要的配置文件。

以上就是vue-cli2 和 vue-cli3 的配置已经项目目录,如有错误,欢迎提出,共同学习。

个人jQuery插件库:http://www.jq22.com/myhome; 个人github地址:https://github.com/zjp2017/

vue-cli2、vue-cli3脚手架详细讲解相关推荐

  1. 30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)

    -----------------------------------------原文链接------------------------------- 30 道 Vue 面试题,内含详细讲解(涵盖入 ...

  2. 30 道 Vue 面试题,内含详细讲解!

    1.说说你对 SPA 单页面的理解,它的优缺点分别是什么? SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML.JavaScript 和 CSS ...

  3. Vue 注意事项,内含详细讲解

    前言 转自[https://mp.weixin.qq.com/s?__biz=MjM5MDA2MTI1MA==&mid=2649091937&idx=1&sn=1d08ebe7 ...

  4. Vue路由(vue-router)详细讲解

    中文文档:https://router.vuejs.org/zh/ Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌.路由实际 ...

  5. Vue路由(vue-router)详细讲解指南

    中文文档:https://router.vuejs.org/zh/ Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌.路由实际 ...

  6. 15道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)

    本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以问题的形式进行整理汇总,意在帮助作者及读者自测下 Vue 掌握的程度. 本文章节结构以从易到难进行组织,建议读者按章节顺序进行 ...

  7. vue学习笔记(超详细)

    文章目录 一. Vue基础 认识Vue.js Vue安装方式 Vue的MVVM 二. Vue基础语法 生命周期 模板语法 创建Vue, options可以放什么 语法 综合 v-on v-for遍历数 ...

  8. 教你用webpack搭一个vue脚手架[超详细讲解和注释!]

    1.适用人群 1.对webpack知识有一定了解但不熟悉的同学.2.女同学!!!(233333....) 2.目的 在自己对webpack有进一步了解的同时,也希望能帮到一些刚接触webpack的同学 ...

  9. 公司项目vue cli2升级到vue cli3

    背景: 公司项目历时时间较长,通过长时间的迭代,目前项目文件较多(src目录下有2217个文件),系统庞大, 之前通过vue cli2脚手架构建的项目框架,在本地开发时已经明显感觉到吃力(项目首次启动 ...

最新文章

  1. python的编程模式-Python 编程,应该养成哪些好的习惯?
  2. springboot脚本启动bat_SpringBoot系列(1)基础入门
  3. Linux workqueue工作原理
  4. 如何修改eclipse里面Android虚拟机的存放路径
  5. 农村人深加工红薯,一招增值数倍,机器一条龙操作省人力
  6. android 开发工具类,Android中常用开发工具类—持续更新...
  7. 基于神经网络的房价预测,BP神经网络预测房价
  8. 舒尔特 Pro ,专业训练注意力专注力
  9. 7-5 体脂率换算(男女皆可计算)
  10. 微信公众号开发(十)模板消息
  11. Python——画一棵漂亮的樱花树(不同种樱花+玫瑰+圣诞树喔
  12. 微服务的优缺点_支付宝上的好医保长期医疗险这款保险到底怎么样?保障全面吗?有哪些优缺点?值得买吗?...
  13. (纯原创)分解质因数
  14. Java实习面试重点基础知识
  15. oracle 磁带备份,磁带备份 - Linux下实现自动备份Oracle数据库_数据库技术_Linux公社-Linux系统门户网站...
  16. 2021年长安杯电子数据取证大赛
  17. springboot-rabbitmq-reply 消息直接回复模式
  18. 《PTA——拼题A》之第1016题
  19. 阿里数据分析试题解析
  20. SEO笔记--代码优化(三)

热门文章

  1. [C++STL]C++实现unordermap容器和unorderset容器
  2. Memento(备忘录)--对象行为型模式
  3. c++中计算2得n次方_七上,一元一次方程,知识点综合学霸笔记在手
  4. 邻接表1 - 试在邻接表存储结构上实现图的基本操作 insert_vertex 和 insert_arc-数据结构-图-icoding
  5. Deeplab 在Qt Creator下编译报错undefined reference to Mat_xxx
  6. Spring boot 启动过程
  7. ARC077E - guruguru(差分)
  8. P1247 取火柴游戏
  9. C - Insertion Sort Gym - 101955C
  10. Network POJ-3694