# webpack_vue_tutorials
**Repository Path**: hwhao/webpack_vue_tutorials
## Basic Information
- **Project Name**: webpack_vue_tutorials
- **Description**: 一步一步搭建webpack+vue项目。
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 7
- **Forks**: 3
- **Created**: 2016-12-19
- **Last Updated**: 2024-11-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# [造轮子教程]十分钟搭建Webpack+Vue项目
> 本教程涉及技术栈和相关工具为:webpack@1,vue@1,vue-router@0.7,vuex@1,eslint
>
> 对于webpack@2和vue@2,请参考官方文档作改动
>
> 如果项目本身并没有特别需求,还是推荐使用`vue-cli`构建项目,方便快捷
推荐vue项目目录结构:
- config 全局变量
- dist 编译后的项目代码
- src 项目源码
- apis api封装
- components Vue组件
- libs js工具类
- router 路由
- index.js 路由对象
- routes.js 路由配置
- store Vuex的store
- modules vuex模块
- types.js type管理
- styles css样式
- views 页面组件
- main.js vue入口文件
- webpack.config Webpack各种环境的配置文件
- package.json
## 第一步:初始化项目
1. 所有项目的第一步当然是:创建项目文件夹,然后使用`npm init -y`创建`package.json`
2. 项目根目录下建立`src`和`dist`文件夹,分别用来存放`项目源码`和`webpack编译后的代码`
## 第二步:入口文件
1. 在`根目录`下直接建立一个`index.html`,作为页面的入口文件
```html
Demo
{{message}}
```
2. 在`src`下建立一个`main.js`,作为Vue的入口文件
```javascript
// import...from的语法是ES6的,需要用到babel,后面再说
// require的语法是Commonjs的,webpack已经实现了,可以直接使用
const Vue = require('vue')
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
```
3. 安装模块
安装Vue:`npm install vue@1 --save`
安装Webpack: `npm install webpack --save-dev`
4. 使用webpack编译打包
除非在全局安装`webpack`,使用本地安装需要在`package.json`的`script`加入运行脚本,添加之后`package.json`如下:
```json
{
"name": "step2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack src/main.js dist/main.js" // <---添加这句
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"vue": "^1.0.28"
},
"devDependencies": {
"webpack": "^1.14.0"
}
}
```
运行`npm run dev`,再用浏览器打开`index.html`就能看到效果了:
```
Hello Vue.js!
```
## 第三步:编写webpack配置文件
上一步中直接使用webpack运行脚本`webpack [入口文件] [出口文件]`,显然对于后期添加webpack插件和不同环境的配置是不行的。
1. 在项目根目录下创建`webpack.config`文件夹专门用于存放webpack的配置文件
2. 为了让配置文件不同的编译环境中能够复用(例如`loaders`的配置,不管在开发环境还是生产环境肯定都是一样的),在`webpack.confg`中首先创建一个`base.js`文件:
```javascript
const path = require('path')
const root = path.resolve(__dirname, '..') // 项目的根目录绝对路径
module.exports = {
entry: path.join(root, 'src/main.js'), // 入口文件路径
output: {
path: path.join(root, 'dist'), // 出口目录
filename: 'main.js' // 出口文件名
}
}
```
上面这段配置就实现了`webpack src/main.js dist/main.js`的功能,还可以额外拓展一下,变成:
```javascript
const path = require('path')
const root = path.resolve(__dirname, '..') // 项目的根目录绝对路径
module.exports = {
entry: path.join(root, 'src/main.js'), // 入口文件路径
output: {
path: path.join(root, 'dist'), // 出口目录
filename: 'main.js' // 出口文件名
},
resolve: {
alias: { // 配置目录别名
// 在任意目录下require('components/example') 相当于require('项目根目录/src/components/example')
components: path.join(root, 'src/components'),
views: path.join(root, 'src/views'),
styles: path.join(root, 'src/styles'),
store: path.join(root, 'src/store')
},
extensions: ['', '.js', '.vue'], // 引用js和vue文件可以省略后缀名
fallback: [path.join(root, 'node_modules')] // 找不到的模块会尝试在这个数组的目录里面再寻找
},
resolveLoader: {
fallback: [path.join(root, 'node_modules')] // 找不到的loader模块会尝试在这个数组的目录里面再寻找
},
module: { // 配置loader
loaders: [
{test: /\.vue$/, loader: 'vue'}, // 所有.vue结尾的文件,使用vue-loader
{test: /\.js$/, loader: 'babel', exclude: /node_modules/} // .js文件使用babel-loader,切记排除node_modules目录
]
}
}
```
根目录下添加`.babelrc`用于配置`babel`:
```json
{
"presets": ["es2015"]
}
```
> 使用了vue-loader和babel-loader需要安装包:
>
> npm install --save-dev vue-loader@8 babel-loader babel-core babel-plugin-transform-runtime babel-preset-es2015 css-loader vue-style-loader vue-hot-reload-api@1 vue-html-loader
3. 在`webpack.confg`创建`dev.js`文件:
```javascript
const path = require('path')
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseConfig = require('./base')
const root = path.resolve(__dirname, '..')
module.exports = merge(baseConfig, {})
```
上面的代码仅仅是导出了跟`base.js`一模一样的配置,下面我们添加更多用于`dev`(开发环境)的配置。
> webpack-merge 用于合并两个配置文件,需要安装
>
> npm install --save-dev webpack-merge
4. 使用webpack dev server,开启一个小型服务器,不需要再手动打开`index.html`进行调试了
修改配置文件为:
```javascript
module.exports = merge(baseConfig, {
devServer: {
historyApiFallback: true, // 404的页面会自动跳转到/页面
inline: true, // 文件改变自动刷新页面
progress: true, // 显示编译进度
colors: true, // 使用颜色输出
port: 3000, // 服务器端口
},
devtool: 'source-map' // 用于标记编译后的文件与编译前的文件对应位置,便于调试
})
```
5. 添加热替换配置,每次改动文件不会再整个页面都刷新
安装`webpack-dev-server`:`npm install --save-dev webpack-dev-server`
```javascript
module.exports = merge(baseConfig, {
entry: [
'webpack/hot/dev-server', // 热替换处理入口文件
path.join(root, 'src/index.js')
],
devServer: { /* 同上 */},
plugins: [
new webpack.HotModuleReplacementPlugin() // 添加热替换插件
]
}
```
6. 使用`HtmlWebpackPlugin`,实现js入口文件自动注入
```javascript
module.exports = merge(baseConfig, {
entry: [ /* 同上 */ ],
devServer: { /* 同上 */ },
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: path.join(root, 'index.html'), // 模板文件
inject: 'body' // js的script注入到body底部
})
]
}
```
最后修改后完整的`dev.js`请查看源码
> 这里的`HotModuleReplacementPlugin`是`webpack`内置的插件,不需要安装
>
> 但`HtmlWebpackPlugin`需要自行安装:
>
> npm install --save-dev html-webpack-plugin
>
> 在文件头中引入`const HtmlWebpackPlugin = require('html-webpack-plugin')`
修改`index.html`,去掉入口文件的引入:
```html
Demo
{{message}}
```
7. 最后修改`package.json`中的webpack运行脚本为:
```json
{
"dev": "webpack-dev-server --config webpack.config/dev.js"
}
```
为了测试webpack配置是否都生效了,下面创建一个vue组件`src/components/Hello.vue`:
```html
{{message}}
```
修改`main.js`:
```javascript
import Vue from 'vue'
import Hello from './components/Hello.vue'
new Vue({
el: '#app',
template: '
',
components: {Hello}
})
```
运行`npm run dev`,浏览器打开`localhost:3000`查看结果:
```
Hello Vue.js!
```
## 第四步:配置路由
1. 安装`vue-router`: `npm install --save vue-router@0.7`
2. 创建目录
在`src`目录下创建`views`文件夹,用于存放页面组件
在`src`目录下创建`router`文件夹,用于存放所有路由相关的配置
3. 添加路由页面
添加页面组件`src/views/Home.vue`:
```html
```
添加`src/router/routes.js`文件,用于配置项目路由:
```javascript
import Home from 'views/Home'
export default {
'/': {
name: 'home',
component: Home
}
}
```
添加路由入口文件`src/router/index.js`:
```javascript
import Vue from 'vue'
import Router from 'vue-router'
import routes from './routes'
Vue.use(Router)
const router = new Router({
hashbang: false, // 关闭hash模式
history: true, // 开启html5history模式
linkActiveClass: 'active' // v-link激活时添加的class,默认是`v-link-active`
})
router.map(routes)
router.beforeEach(({to, next}) => {
console.log('---------> ' + to.name) // 每次调整路由时打印,便于调试
next()
})
export default router
```
修改`main.js`:
```javascript
import Vue from 'vue'
import router from './router'
const App = Vue.extend({})
router.start(App, '#app')
```
最后别忘了编辑`index.html`:
```html
Demo
```
重新执行`npm run dev`,浏览器打开`localhost:3000`查看效果
## 第五步:配置Vuex
> vuex通常用于存放和管理不同组件中的共用状态,例如不同路由页面之间的公共数据
>
> vuex中的几个概念:
>
> state:状态,即数据
>
> store:数据的集合,一个vuex引用,仅有一个store,包含n个state
>
> mutation:state不能直接赋值,通过mutation定义最基本的操作
>
> action:在action中调用一个或多个mutation
>
> getter:state不能直接取值,使用getter返回需要的state
>
> module:store和state之间的一层,便于大型项目管理,store包含多个module,module包含state、mutation和action
>
> 本教程中将以一个全局计数器作为例子
1. 安装vuex
安装`vuex`:`npm install --save vuex@1`
添加`src/store`文件夹,存放vuex相关文件,添加`src/store/modules`用于vuex分模块管理
2. 添加`src/store/types.js`,vuex的所有`mutation type`都放在一起,不建议分开多个文件,有效避免重名情况:
```javascript
export const INCREASE = 'INCREASE' // 累加
export const RESET = 'RESET' // 清零
```
3. 编写vuex模块,添加`counter`模块目录`store/modules/counter`
添加`store/modules/counter/actions.js`:
```javascript
import {INCREASE, RESET} from 'store/types'
export const increase = (({dispatch}) => {
dispatch(INCREASE) // 调用type为INCREASE的mutation
})
export const reset = (({dispatch}) => {
dispatch(RESET) // 调用type为RESET的mutation
})
```
添加`store/modules/counter/index.js`
```javascript
import{INCREASE, RESET} from 'store/types.js'
const state = {
count: 0
}
const mutations = {
[INCREASE] (state) { state.count++ },
[RESET] (state) { state.count = 0 }
}
export default {state, mutations}
```
4. 添加`store/index.js`,作为vuex入口文件
```javascript
import Vue from 'vue'
import Vuex from 'vuex'
import counter from 'store/modules/counter'
Vue.use(Vuex) // 确保在new Vuex.Store()之前
export default new Vuex.Store({
modules: {counter}
})
```
5. 修改`main.js`,将store引入并添加到App中:
```javascript
import Vue from 'vue'
import router from './router'
import store from 'store'
const App = Vue.extend({store})
router.start(App, '#app')
```
6. 最后改造一下`src/components/Hello.vue`,把action用上:
```html
{{message}}
click count: {{count}}
```
## 第六步:配置eslint
> eslint不是必须的,但是强烈建议用在所有的javascript项目中
>
> 对于个人开发,可以在编程过程中发现并提示语法错误,有效过滤各种低级错误
>
> 对于团队开发,强制采用一致的编码风格,保证项目的统一性,有效避免各种任性行为
>
> 但是一定要注意,eslint定义的只是编码风格,规则是死的,人是活的,学会利用自定义规则的功能,增减规则
>
> 同时要知道,eslint检测不通过,不一定就是不能运行的,可能只是这种写法违背了编码风格,学会查看控制的查找具体错误原因
>
> 想要更好的eslint体验,请根据不同编辑器安装对应的eslint插件,主流的编辑器均已有相应插件
1. 选择合适的编码风格
> eslint提供了许多[rules](http://eslint.org/docs/rules),可以直接在`.eslintrc`文件的`rules`中一个一个的配置
>
> 显然我们大多数情况下不需要这么做,网上已经有一些比较多人使用的风格了,本文推荐使用[standard](https://github.com/feross/standard)
2. 配置`.eslintrc`文件
根目录下创建`.eslintrc`文件:
```json
{
"parser": "babel-eslint", // 支持babel
"extends": "standard", // 使用eslint-config-standard的配置
"plugins": [
"html" // 支持.vue文件的检测
],
"env": {
"browser": true, // 不会将window上的全局变量判断为未定义的变量
"es6": true // 支持es6的语法
},
"rules": { // 自定义个别规则写在这,0忽略,1警告,2报错
"no-unused-vars": 1 // 将”未使用的变量“调整为警告级别,原为错误级别,更多规则请看官网
}
}
```
结合不同编辑器的插件,打开js和vue文件中,就能看到提示了
> 根据使用的不同风格,安装所需的包,本文安装:
>
> npm install --save-dev eslint babel-eslint eslint-config-standard eslint-plugin-standard eslint-plugin-html eslint-plugin-promise
## 第七步:webpack生产环境配置
前面已经配置过了开发环境下使用的配置文件`dev.js`,对于生产环境,通常需要对编译出来的文件进行压缩处理,提取公共模块等等,就需要专门提供一个配置文件
1. 添加`webpack.config/pro.js`文件,把生产环境用不到的删掉,比如`webpack-dev-server`、`webpack-hot-replacement`
```javascript
const path = require('path')
const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const baseConfig = require('./base')
const root = path.resolve(__dirname, '..')
module.exports = merge(baseConfig, {
plugins: [
new HtmlWebpackPlugin({
template: path.join(root, 'index.html'), // 模板文件
inject: 'body' // js的script注入到body底部
})
]
})
```
> webpack常用插件:
>
> extract-text-webpack-plugin 提取css到单独的文件
>
> compression-webpack-plugin 压缩gzip
>
> webpack.optimize.UglifyJsPlugin 压缩js文件,内置插件
>
> webpack.DefinePlugin 定义全局变量,内置插件
>
> webpack.optimize.CommonsChunkPlugin 提取公共依赖,内置插件
>
> 根据项目需求添加相应的插件,插件配置参数请查看官方文档,这里不进行罗列
2. 在`package.json`中添加运行脚本:`"build": "webpack --config webpack.config/pro.js"`
3. 运行`npm run build`,可以在`dist`文件夹中看到打包好的文件
## 完
“十分钟”只是噱头,多配几次,十分钟都不用。
轮子虽然都是圆的,也有轻重宽窄之分,造一辆车有时候也避免不了重造一个轮子。