使用vue-cli有时会出现一些莫名的问题,清楚项目的结构文件及其意义方便更好的开发和解决问题,介绍如下:
build/ // 项目构建(webpack)相关代码
build.js // 生产环境构建代码
check-versions.js // 检查node&npm等版本
utils.js // 构建配置公用工具
vue-loader.conf.js // vue加载器
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 // 测试环境变量
dist/ //npm run build打包后生成的文件夹
node_modules/
... // 项目依赖的模块
src/ // 源码目录
assets/ // 资源目录
logo.png
components/ // vue公共组件
Head.vue
Footer.vue
pages (或views)/ //视图
login/
Index.vue
list/
Foods.vue
router/ // 前端路由
index.js// 路由配置文件
store/ // vuex的状态管理
App.vue// 页面入口文件(根组件)
main.js// 程序入口文件(入口js文件)
static // 静态文件,比如一些图片,json数据等
.gitkeep //这个里面的gitkeep是这个目录为空,也可以把这个目录提交的git仓库里面,因为通常一个空目录是不能提交git仓库里面的
.babelrc// ES6语法编译配置
.editorconfig// 定义代码格式
.gitignore// git上传需要忽略的文件格式
index.html// 入口页面
package.json// 项目基本信息
README.md// 项目说明
build.js
require('./check-versions')() // 检查 Node 和 npm 版本
process.env.NODE_ENV = 'production'
const ora = require('ora') // 一个很好看的 loading 插件
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config') // 加载 config.js
const webpackConfig = require('./webpack.prod.conf') // 加载 webpack.prod.conf
const spinner = ora('building for production...')
spinner.start() // 开始 loading 动画
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')
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'
))
})
})
webpack.dev.conf.js
const utils = require('./utils') // 使用一些小工具
const webpack = require('webpack') // 使用 webpack
const config = require('../config') // 使用 config/index.js
const merge = require('webpack-merge') // 使用 webpack 配置合并插件
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf') // 加载 webpack.base.conf
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 使用 html-webpack-plugin 插件,这个插件可以帮我们自动生成 html 并且注入到 .html 文件中
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
// 将我们 webpack.dev.conf.js 的配置和 webpack.base.conf.js 的配置合并
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
// 使用 styleLoaders
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false, // since we use CopyWebpackPlugin.
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, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
// definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
// HotModule 插件在页面进行变更的时候只会重回对应的页面模块,不会重绘整个 html 文件
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
// 使用了 NoErrorsPlugin 后页面中的报错不会阻塞,但是会在编译结束后报错
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
// 将 index.html 作为入口,注入 html 代码后生成 index.html文件
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
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 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)
}
})
})
webpack.base.conf.js
const path = require('path') // 使用 NodeJS 自带的文件路径插件
const utils = require('./utils') // 引入一些小工具
var webpack = require('webpack')
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'
},
// webpack输出路径和命名规则
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'],
// 别名,方便引用模块,例如有了别名之后,
// import Vue from 'vue/dist/vue.esm.js'可以写成 import Vue from 'vue'
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
// 不同类型模块的处理规则
module: {
rules: [
...
// 需要处理的文件及使用的 loader
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
],
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'
}
}
config/index.js
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
// 开发过程中使用的配置
dev: {
// Paths // 编译输出的二级目录
assetsSubDirectory: 'static',
// 编译发布上线路径的根目录,可配置为资源服务器域名或 CDN 域名
assetsPublicPath: '/',
// 需要 proxyTable 代理的接口(可跨域)
proxyTable: {},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false, // 是否自动打开浏览器
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map', //可改变为devtool: '#eval-source-map',方便调试
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
// 构建产品时使用的配置
build: {
// Template for index.html // html入口文件
index: path.resolve(__dirname, '../dist/index.html'),
// Paths // 编译输出的静态资源根路径
assetsRoot: path.resolve(__dirname, '../dist'),
// 编译输出的二级目录
assetsSubDirectory: 'static',
// 编译发布上线路径的根目录,可配置为资源服务器域名或 CDN 域名
assetsPublicPath: './',
/**
* Source Maps
*/
// 是否开启 cssSourceMap
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
// 是否开启 gzip
productionGzip: false,
// 需要使用 gzip 压缩的文件扩展名
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
}
webpack.dev.conf.js
const path = require('path')
const utils = require('./utils') // 使用一些小工具
const webpack = require('webpack')
const config = require('../config') // 加载 confi.index.js
const merge = require('webpack-merge') // 加载 webpack 配置合并工具
const baseWebpackConfig = require('./webpack.base.conf') // 加载 webpack.base.conf.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 一个可以插入 html 并且创建新的 .html 文件的插件
const ExtractTextPlugin = require('extract-text-webpack-plugin') // 一个 webpack 扩展,可以提取一些代码并且将它们和文件分离开,如果我们想将 webpack 打包成一个文件 css js 分离开,那我们需要这个插件
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const env = require('../config/prod.env')
// 合并 webpack.base.conf.js
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
// 是否使用 #source-map 开发工具
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
// 编译输出目录
path: config.build.assetsRoot,
// 编译输出文件名
// 我们可以在 hash 后加 :6 决定使用几位 hash 值
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
// definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
new webpack.DefinePlugin({
'process.env': env
}),
new UglifyJsPlugin({ // 压缩 js (同样可以压缩 css)
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.
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
new HtmlWebpackPlugin({ // 输入输出的 .html 文件
filename: config.build.index,
template: 'index.html',
inject: true,
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 CommonsChunkPlugin
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
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
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
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
// 开启 gzip 的情况下使用下方的配置
if (config.build.productionGzip) {
// 加载 compression-webpack-plugin 插件
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
// 使用 compression-webpack-plugin 插件进行压缩
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').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
.babelrc
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}
.editorconfig
root = true
[*] // 对所有文件应用下面的规则
charset = utf-8 // 编码规则用utf-8
indent_style = space // 缩进用空格
indent_size = 2 // 缩进数量为2个空格
end_of_line = lf // 换行符格式
insert_final_newline = true // 是否在文件的最后插入一个空行
trim_trailing_whitespace = true // 是否删除行尾的空格
以上是经过收集跟总结的部分,还有许多需要完善,请注意版本,自己尝试合适的才是好的。纸上得来终觉浅,绝知此事要躬行!
完善中……