使用vue-cli 3.x构建新项目
之前使用vue-cli2.0构建的多页项目,对脚手架扩展了一些功能,但是存在一些问题,趁现在升级了vue-cli 3.x顺便把项目重构一下
扩展点
改造 vue 项目为多页(多模块)、多应用,和单页(单模块)共存的项目
改造npm run dev命令,支持单模块启动调试服务 和 全量项目启动调试服务
改造npm run build命令,改为构建指定应用并打包部署到不同的服务环境
复制代码
为什么扩展?
vue-cli 2.0版本官方不支持多页,且2.0使用的webpack构建任务不支持多线程以及DLL,全靠自己扩展,不便于维护。vue-cli 2.0在多页数量较多的情况下,不管本地热更新还是构建打包,都是非常慢的。 现在的工程大多存在多个子应用,且多个子应用通常使用一套组件,一套公共方法,但是子应用采用单独发包迭代。所以支持多应用是非常有必要的
新建vue-cli 3.0项目
这个网上很多教程,这里就说了,这篇文件讲的很详细
[使用 vue-cli 3 快速创建 Vue 项目](https://segmentfault.com/a/1190000014627083)
复制代码
vue-cli 3.0官方支持多页,重点在于vue.config.js文件的配置
const path = require('path');
// 新建一个multipage.js文件,用来处理vue加载模板的入口;
const pages = require('./config/multipage').getPages();
module.exports = {
// 官方要求修改路径在这里做更改,默认是根目录下,可以自行配置
baseUrl: './',
lintOnSave: false,
productionSourceMap: false,
// 在多核机器下会默认开启。
parallel: require('os').cpus().length > 1,
pages,
css: { // css相关配置
extract: true, // 是否使用css分离插件 ExtractTextPlugin
sourceMap: false, // 开启 CSS source maps?
loaderOptions: {
less: {
javascriptEnabled: true
}
}, // css预设器配置项
modules: false // 启用 CSS modules for all css / pre-processor files.
},
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.module.rule('images').use('url-loader').loader('url-loader').tap(options => {
options.name = 'static/img/[name].[hash:8].[ext]';
return options;
});
config.plugin('extract-css').tap(() => [
{
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].css'
}
]);
}
},
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.output.path = path.join(__dirname, './dist')
config.output.filename = 'static/js/[name].[contenthash:8].js'
config.output.chunkFilename = 'static/js/[name].[contenthash:8].js'
}
Object.assign(config, {
// 打包时webpack不打包进去
externals: [
{'vue': 'window.Vue'},
{'vue-router': 'window.VueRouter'}
],
// 开发生产共同配置
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'assets': path.resolve(__dirname, './src/assets'),
'common': path.resolve(__dirname, './src/common'),
'components': path.resolve(__dirname, './src/components'),
'pages': path.resolve(__dirname, './src/pages'),
'vue$': 'vue/dist/vue.esm.js'
}
}
});
}
};
复制代码
说下配置文件踩的坑
if (process.env.NODE_ENV === 'production') {
config.output.path = path.join(__dirname, './dist')
config.output.filename = 'static/js/[name].[contenthash:8].js'
// 这里是不支持直接修改publicPath路径的,必须用官方推荐的 baseUrl。
// config.output.publicPath = './'
config.output.chunkFilename = 'static/js/[name].[contenthash:8].js'
}
复制代码
最后打包出来的目录格式是这样的
multipage.js文件
const path = require('path');
const fs = require('fs');
const URL = process.env.url; // 默认只加载一个文件 singlepage || multipage
const NODE_ENV = process.env.NODE_ENV; // process环境变量
if (NODE_ENV === 'production' && URL === undefined) throw new Error('当前打包命令缺少url参数!')
const config = {
entry: 'index.js',
html: 'index.html',
pagesRoot: path.resolve(__dirname, '../src/pages')
};
const getRoutes = () => {
const allRoutes = [];
const findAllRoutes = (source, routes) => {
const globFiles = fs.readdirSync(source);
// 有URL 就默认加载那个指定的项目, 没有就加载全部的 [ *.js ];
const files = URL ? [globFiles.find(item => item.includes(URL))] : globFiles;
files.forEach(filename => {
const fullname = path.join(source, filename);
const stats = fs.statSync(fullname);
if (!stats.isDirectory()) return;
// 检测给定的路径是否存在。
if (fs.existsSync(`${fullname}/${config.html}`)) {
routes.push(fullname);
} else {
findAllRoutes(fullname, routes);
}
});
};
findAllRoutes(config.pagesRoot, allRoutes);
return allRoutes;
};
const getPages = () => {
const pages = {};
getRoutes().forEach(route => {
let filename = route.slice(config.pagesRoot.length + 1);
pages[filename] = {
entry: `${route}/${config.entry}`,
template: `${route}/${config.html}`,
// 兼容dev开发模式时 serve 全量项目和单个项目
filename: URL ? config.html : `${filename}/${config.html}`
};
});
// console.log(pages);
return pages;
};
module.exports = {
getRoutes,
getPages
}
复制代码
src 目录下
启动项目 dev
1. npm run dev (启动全部项目) 包含多页项目 和 单页项目
2. 建议启动单个项目,编译时间短,启动快 ( url=项目名 npm run dev )
复制代码
打包项目并一键部署到测试环境
url=项目名 npm run testbuild
这里打包后是使用node.js实现的自动上传;config文件下的upload.js文件我之前介绍过可以看我上一篇文章。
复制代码
"scripts": {
"dev": "vue-cli-service serve --open",
"lint": "vue-cli-service lint",
"testbuild": "vue-cli-service build && cross-env NODE_CONFIG=test node config/upload"
},
复制代码
cli3.x以后尤大进行了更深的封装, 启动或者打包都是依靠这个vue-cli-service去执行的;
// 源码部分位置 node_modules\@vue\cli-service\bin\vue-cli-service.js
#!/usr/bin/env node
const semver = require('semver')
const { error } = require('@vue/cli-shared-utils')
const requiredVersion = require('../package.json').engines.node
if (!semver.satisfies(process.version, requiredVersion)) {
error(
`You are using Node ${process.version}, but vue-cli-service ` +
`requires Node ${requiredVersion}.\nPlease upgrade your Node version.`
)
process.exit(1)
}
const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
// 主要核心功能在这里;
const rawArgv = process.argv.slice(2)
const args = require('minimist')(rawArgv)
const command = args._[0]
// 这里根据command的结果去执行是 run server 还是run build ;
service.run(command, args, rawArgv).catch(err => {
error(err)
process.exit(1)
})
复制代码
使用感受
修改后整体使用下来,无论是本地开发编译,还是打包项目,提升都很明显,感觉至少提升80%;
原因:cli3.x 升级了webpack4, 配置了多线程提升了速度,使用了缓存,有些公共文件不会被再次打包编译;
复制代码
欢迎加我qq一起探讨学习3544757498;
下一篇介绍本项目的技术选型和项目优化;