简单vue项目脚手架
简单vue项目脚手架
github地址
使用技术栈
webpack(^2.6.1)
webpack-dev-server(^2.4.5)
vue(^2.3.3)
vuex(^2.3.1)
vue-router(^2.5.3)
vue-loader(^12.2.1)
eslint(^3.19.0)
需要学习的知识
vue.js
vuex
vue-router
vue-loader
webpack2
eslint
内容相当多,尤其是webpack2教程,官方脚手架vue-cli虽然相当完整齐全,但是修改起来还是挺花时间,于是自己参照网上的资料和之前做过的项目用到的构建工具地去写了一个简单vue项目脚手架。适用于多页面spa模式的业务场景(每个模块都是一个spa)。比较简单,主要就是一个webpack.config.js文件,没有说特意地去划分成分webpack.dev.config.js、webpack.prov.config.js等等。下面是整个webpack.config.js文件代码:
const { resolve } = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const glob = require('glob')
module.exports = (options = {}) => {
// 配置文件,根据 run script不同的config参数来调用不同config
const config = require('./config/' + (process.env.npm_config_config || options.config || 'dev'))
// 遍历入口文件,这里入口文件与模板文件名字保持一致,保证能同时合成HtmlWebpackPlugin数组和入口文件数组
const entries = glob.sync('./src/modules/*.js')
const entryJsList = {}
const entryHtmlList = []
for (const path of entries) {
const chunkName = path.slice('./src/modules/'.length, -'.js'.length)
entryJsList[chunkName] = path
entryHtmlList.push(new HtmlWebpackPlugin({
template: path.replace('.js', '.html'),
filename: 'modules/' + chunkName + '.html',
chunks: ['manifest', 'vendor', chunkName]
}))
}
// 处理开发环境和生产环境ExtractTextPlugin的使用情况
function cssLoaders(loader, opt) {
const loaders = loader.split('!')
const opts = opt || {}
if (options.dev) {
if (opts.extract) {
return loader
} else {
return loaders
}
} else {
const fallbackLoader = loaders.shift()
return ExtractTextPlugin.extract({
use: loaders,
fallback: fallbackLoader
})
}
}
const webpackObj = {
entry: Object.assign({
vendor: ['vue', 'vuex', 'vue-router']
}, entryJsList),
// 文件内容生成哈希值chunkhash,使用hash会更新所有文件
output: {
path: resolve(__dirname, 'dist'),
filename: options.dev ? 'static/js/[name].js' : 'static/js/[name].[chunkhash].js',
chunkFilename: 'static/js/[id].[chunkhash].js',
publicPath: config.publicPath
},
externals: {
},
module: {
rules: [
// 只 lint 本地 *.vue 文件,需要安装eslint-plugin-html,并配置eslintConfig(package.json)
{
enforce: 'pre',
test: /.vue$/,
loader: 'eslint-loader',
exclude: /node_modules/
},
/*
http://blog.guowenfh.com/2016/08/07/ESLint-Rules/
http://eslint.cn/docs/user-guide/configuring
[eslint资料]
*/
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader']
},
// 需要安装vue-template-compiler,不然编译报错
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
sass: cssLoaders('vue-style-loader!css-loader!sass-loader', { extract: true })
}
}
},
{
// 需要有相应的css-loader,因为第三方库可能会有文件
// (如:element-ui) css在node_moudle
// 生产环境才需要code抽离,不然的话,会使热重载失效
test: /\.css$/,
use: cssLoaders('style-loader!css-loader')
},
{
test: /\.(scss|sass)$/,
use: cssLoaders('style-loader!css-loader!sass-loader')
},
{
test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/imgs/[name].[ext]?[hash]'
}
}
]
}
]
},
plugins: [
...entryHtmlList,
// 抽离css
new ExtractTextPlugin({
filename: 'static/css/[name].[chunkhash].css',
allChunks: true
}),
// 抽离公共代码
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest']
}),
// 定义全局常量
// cli命令行使用process.env.NODE_ENV不如期望效果,使用不了,所以需要使用DefinePlugin插件定义,定义形式'"development"'或JSON.stringify('development')
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: options.dev ? JSON.stringify('development') : JSON.stringify('production')
}
})
],
resolve: {
// require时省略的扩展名,不再需要强制转入一个空字符串,如:require('module') 不需要module.js
extensions: ['.js', '.json', '.vue', '.scss', '.css'],
// require路径简化
alias: {
'~': resolve(__dirname, 'src'),
// Vue 最早会打包生成三个文件,一个是 runtime only 的文件 vue.common.js,一个是 compiler only 的文件 compiler.js,一个是 runtime + compiler 的文件 vue.js。
// vue.js = vue.common.js + compiler.js,默认package.json的main是指向vue.common.js,而template 属性的使用一定要用compiler.js,因此需要在alias改变vue指向
vue: 'vue/dist/vue'
},
// 指定import从哪个目录开始查找
modules: [
resolve(__dirname, 'src'),
'node_modules'
]
},
// 开启http服务,publicPath => 需要与Output保持一致 || proxy => 反向代理 || port => 端口号
devServer: config.devServer ? {
port: config.devServer.port,
proxy: config.devServer.proxy,
publicPath: config.publicPath,
stats: { colors: true }
} : undefined,
// 屏蔽文件超过限制大小的warn
performance: {
hints: options.dev ? false : 'warning'
},
// 生成devtool,保证在浏览器可以看到源代码,生产环境设为false
devtool: 'inline-source-map'
}
if (!options.dev) {
webpackObj.devtool = false
webpackObj.plugins = (webpackObj.plugins || []).concat([
// 压缩js
new webpack.optimize.UglifyJsPlugin({
// webpack2,默认为true,可以不用设置
compress: {
warnings: false
}
}),
// 压缩 loaders
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
return webpackObj
}
上面的代码对于每个配置项都有注释说明,这里有几点需要注意的:
1. webpack.config.js导出的是一个function
之前项目的webpack.config.js是以对象形式export的,如下
module.exports = {
entry: ...,
output: {
...
},
...
}
而现在倒出来的是一个function,如下:
module.exports = (options = {}) => {
return {
entry: ...,
output: {
...
},
...
}
}
这样的话,function会在执行webpack CLI的时候获取webpack的参数,通过options传进function,看一下package.json:
"local": "npm run dev --config=local",
"dev": "webpack-dev-server -d --hot --inline --env.dev --env.config dev",
"build": "rimraf dist && webpack -p --env.config prod" //rimraf清空dist目录
对于local命令,我们执行的是dev命令,但是在最后面会--config=local,这是配置,这样我们可以通过process.env.npm_config_config获取到,而对于dev命令,对于--env XXX,我们便可以在function获取option.config= 'dev' 和 option.dev= true的值,特别方便!以此便可以同步参数来加载不同的配置文件了。对于-d、-p不清楚的话,可以这里查看,很详细!
// 配置文件,根据 run script不同的config参数来调用不同config
const config = require('./config/' + (process.env.npm_config_config || options.config || 'dev'))
2. modules放置模板文件、入口文件、对应模块的vue文件
将入口文件和模板文件放到modules目录(名字保持一致),webpack文件会通过glob读取modules目录,遍历生成入口文件对象和模板文件数组,如下:
const entries = glob.sync('./src/modules/*.js')
const entryJsList = {}
const entryHtmlList = []
for (const path of entries) {
const chunkName = path.slice('./src/modules/'.length, -'.js'.length)
entryJsList[chunkName] = path
entryHtmlList.push(new HtmlWebpackPlugin({
template: path.replace('.js', '.html'),
filename: 'modules/' + chunkName + '.html',
chunks: ['manifest', 'vendor', chunkName]
}))
}
对于HtmlWebpackPlugin插件中几个配置项的意思是,template:模板路径,filename:文件名称,这里为了区分开来模板文件我是放置在dist/modules文件夹中,而对应的编译打包好的js、img(对于图片我们是使用file-loader、url-loader进行抽离,对于这两个不是很理解的,可以看这里)、css我也是会放在dist/下对应目录的,这样目录会比较清晰。chunks:指定插入文件中的chunk,后面我们会生成manifest文件、公共vendor、以及对应生成的jscss(名称一样)
3. 处理开发环境和生产环境ExtractTextPlugin的使用情况
开发环境,不需要把css进行抽离,要以style插入html文件中,可以很好实现热替换
生产环境,需要把css进行抽离合并,如下(根据options.dev区分开发和生产):
// 处理开发环境和生产环境ExtractTextPlugin的使用情况
function cssLoaders(loader, opt) {
const loaders = loader.split('!')
const opts = opt || {}
if (options.dev) {
if (opts.extract) {
return loader
} else {
return loaders
}
} else {
const fallbackLoader = loaders.shift()
return ExtractTextPlugin.extract({
use: loaders,
fallback: fallbackLoader
})
}
}
...
// 使用情况
// 注意:需要安装vue-template-compiler,不然编译会报错
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
sass: cssLoaders('vue-style-loader!css-loader!sass-loader', { extract: true })
}
}
},
...
{
test: /\.(scss|sass)$/,
use: cssLoaders('style-loader!css-loader!sass-loader')
}
再使用ExtractTextPlugin合并抽离到static/css/目录
4. 定义全局常量
cli命令行(webpack -p)使用process.env.NODE_ENV不如期望效果,使用不了,所以需要使用DefinePlugin插件定义,定义形式'"development"'或JSON.stringify(process.env.NODE_ENV),我使用这样的写法'development',结果报错(针对webpack2),查找了一下网上资料,它是这样讲的,可以去看一下,设置如下:
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: options.dev ? JSON.stringify('development') : JSON.stringify('production')
}
})
5. 使用eslint修正代码规范
通过eslint来检查代码的规范性,通过定义一套配置项,来规范代码,这样多人协作,写出来的代码也会比较优雅,不好的地方是,就是配置项太多,有些默认项设置我们不需要,但是确是处处限制我们,需要通过配置屏蔽掉,可以通过.eslintrc 文件或是package.json的eslintConfig,还有其他方式,可以到中文网看,这里我用的是package.json方式,如下:
...
"eslintConfig": {
"parser": "babel-eslint",
"extends": "enough",
"env": {
"browser": true,
"node": true,
"commonjs": true,
"es6": true
},
"rules": {
"linebreak-style": 0,
"indent": [2, 4],
"no-unused-vars": 0,
"no-console": 0
},
"plugins": [
"html"
]
},
...
我们还需要安装 npm install eslint eslint-config-enough eslint-loader --save-dev,eslint-config-enough是所谓的配置文件,这样package.json的内容才能起效,但是不当当是这样,对应编辑器也需要安装对应的插件,sublime text 3需要安装SublimeLinter、SublimeLinter-contrib-eslint插件。对于所有规则的详解,可以去看官网,也可以去这里看,很详细!
由于我们使用的是vue-loader,自然我们是希望能对.vue文件eslint,那么需要安装eslint-plugin-html,在package.json中进行配置。然后对应webpack配置:
{
enforce: 'pre',
test: /.vue$/,
loader: 'eslint-loader',
exclude: /node_modules/
}
我们会发现webpack v1和v2之间会有一些不同,比如webpack1对于预先加载器处理的执行是这样的,
module: {
preLoaders: [
{
test: /\.js$/,
loader: "eslint-loader"
}
]
}
更多的不同可以到中文网看,很详细,不做拓展。
6. alias vue指向问题
...
alias: {
vue: 'vue/dist/vue'
},
...
Vue 最早会打包生成三个文件,一个是 runtime only 的文件 vue.common.js,一个是 compiler only 的文件 compiler.js,一个是 runtime + compiler 的文件 vue.js。
vue.js = vue.common.js + compiler.js,默认package.json的main是指向vue.common.js,而template 属性的使用一定要用compiler.js,因此需要在alias改变vue指向
7. devServer的使用
之前的项目中使用的是用express启动http服务,webpack-dev-middleware+webpack-hot-middleware,这里会用到compiler+compilation,这个是webpack的编译器和编译过程的一些知识,也不是很懂,后续要去做做功课,应该可以加深对webpack运行机制的理解。这样做的话,感觉复杂很多,对于webpack2.0 devServer似乎功能更强大更加完善了,所以直接使用就可以了。如下:
devServer: {
port: 8080, //端口号
proxy: { //方向代理 /api/auth/ => http://api.example.dev
'/api/auth/': {
target: 'http://api.example.dev',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
},
publicPath: config.publicPath,
stats: { colors: true }
}
//changeOrigin会修改HTTP请求头中的Host为target的域名, 这里会被改为api.example.dev
//pathRewrite用来改写URL, 这里我们把/api前缀去掉,直接使用/auth/请求
webpack 2 打包实战讲解得非常好,非常棒。可以去看一下,一定会有所收获!
8. 热重载原理
webpack中文网,讲的还算清楚,不过可能太笨,看起来还是云里雾里的,似懂非懂的,补补课,好好看看。
9. localtunnel的使用
Localtunnel 是一个可以让内网服务器暴露到公网上的开源项目,使用可以看这里,
$ npm install -g localtunnel
$ lt --port 8080
your url is: https://uhhzexcifv.localtunnel.me
这样的话,可以把我们的本地网站暂时性地暴露到公网,可以对网站做一些线上线下对比,详细内容可以去了解一下localtunnel,这里讲的是通过上面配置,访问https://uhhzexcifv.localtunnel.me,没有达到理想效果,出现了Invalid Host header的错误,因为devServer缺少一个配置disableHostCheck: true,这样的一个配置,很多文档上面都没有说明,字面上面的意思不要去检查Host,这样设置,便可以绕过这一层检验,设置的配置项在optionsSchema.json中,issue可以看这里
简单vue项目脚手架的更多相关文章
- 简单vue项目脚手架(vue+webpack2.0+vuex+vue-router)
github地址 使用技术栈 webpack(^2.6.1) webpack-dev-server(^2.4.5) vue(^2.3.3) vuex(^2.3.1) vue-router(^2.5.3 ...
- 分享一个vue项目“脚手架”项目的实现步骤
搭建缘由 源于公司每次新启动一个由多人协同开发的项目都由负责人初始化项目之后,每个人再去从私服pull一下项目才开始开发.但是每次初始化工程都是一步步的造轮子,一个个依赖去安装,新建一个个不同功能的文 ...
- webpack工具学习 构建简单vue项目(不依赖vue-cli) webpack4.0
目的用webpack构建简单前端项目 1.npm init (npm init -y) 形成package.json 2.npm install --save-dev webpack 形成 n ...
- vue项目搭建及创建、目录结构、项目启动、全局配置
Vue项目环境搭建 """ node ~~ python:node是用c++编写用来运行js代码的 npm(cnpm) ~~ pip:npm是一个终端应用商城,可以换国内 ...
- day66_10_10,vue项目环境搭建
一.下载. 首先去官网查看网址. 下载vue环境之前需要先下载node,使用应用商城npm下载,可以将其下载源改成cnpm: """ node ~~ python:nod ...
- Vue框架(三)——Vue项目搭建和项目目录介绍、组件、路由
Vue项目环境搭建 1) 安装node,在官网下载好,然后在本地安装 官网下载安装包,傻瓜式安装:https://nodejs.org/zh-cn/ 2) 换源安装cnpm >: npm ins ...
- Vue 项目环境搭建
Vue项目环境搭建 ''' 1) 安装node 官网下载安装包,傻瓜式安装:https://nodejs.org/zh-cn/ 2) 换源安装cnpm >: npm install -g cnp ...
- 如何创建vue项目
Vue项目环境搭建 """ node ~~ python:node是用c++编写用来运行js代码的 npm(cnpm) ~~ pip:npm是一个终端应用商城,可以换国内 ...
- vue项目配置及项目初识
目录 Vue项目环境搭建 Vue项目创建 重构项目依赖 1.需要转移的文件 2.重构依赖 pycharm配置并启动vue项目 vue项目目录结构分析 vue组件(.vue文件) 全局脚本文件main. ...
随机推荐
- java数组复习和内存分配
Java基础知识复习 1.循环 1.1. for循环 for(int i =1;i<=10;i++){ System.out.println("Hello world"+i) ...
- angular批量上传图片并进行校验
最近做一个项目,有一个批量上传图片,并校验是否是图片和上传最大数量的需求.下面分享一下我的想法,欢迎大神探讨. 首先是在html中支持批量上传和接收图片(mac下设置了之后不存在类型校验),下面上ht ...
- 用iptables封杀内网的bt软件
我所在的网络情况是这样的!1台FC3和3台win2000组成一个局域网!四台机都接在100m的交换机上.在FC3上有两个网卡eth0接外网 adsl eth1接在交换机.FC3做nat带3台win20 ...
- Java基础——基本类型包装类
一.概述: 将基本数据类型封装成对象 优点: 可以在对象中定义更多的功能方法操作该数据 常见用法: 用于基本类型与字符串之间的转换 基本数据类型 包装类 byte Byte short Short i ...
- web服务器-Nginx下载限速
web服务器-Nginx下载限速 一. 限速介绍 在生产环境中,为了保护WEB服务器的安全,我们都会对用户的访问做出一些限制,保证服务器的安全及资源的合理分配. 限流(rate limiting)是N ...
- contos 配置国内yum源
contos配置国内yum源 前言 rpm管理软件包的命令,很难用,需要手动解决以来关系,所以最好用 yum 的理念是使用一个中心仓库(repository)管理一部分甚至一个distribution ...
- ssh端口转发学习笔记
ssh端口转发学习笔记 ssh命令参数介绍 -C 压缩数据传输 -f 将 ssh 转到后台运行,即认证之后,ssh 自动以后台运行.不在输出信息 -n 将 stdio 重定向到 /dev/null,与 ...
- JS如何通过月份,计算月份相差几个月
1 var tr = ''; 2 <script> 3 $.each(data, function (index, item) { 4 let startTime = new Date(i ...
- java面向对象思想之继承
一.什么是继承 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为.可以联系生活进行理解,相当于父亲和儿子的关系.父亲有的属 ...
- 半吊子菜鸟学Web开发6 -- Vscode开发环境配置
1vscode上手一周不到,终于弄出点门路,终于弄清楚了点vscode的设置是什么样子的了....哭 2就我这两天的使用来看,一般vscode默认只让打开一个文件夹,然后在你打开的文件夹里面自动生成 ...