详解如何从零开始搭建Express+Vue开发环境


Posted in Javascript onJuly 17, 2018

准备工作

1. 为前端选择合适的预处理工具和资源管理工具

预处理工具又分为 js 预处理工具和 css 预处理工具。Javascript 一直以来最为人诟病的一点就是缺乏原生的模块机制,所有 js 代码文件在被 html 页面引入后将共用同一个命名空间。所以才出现了各种“标准”尝试解决这个问题,但他们都不是原生的,需要额外的工具对代码进行特殊处理。虽然 ES6 终于引入了模块机制,但以现在的浏览器支持程度,还不足以“毫无顾虑地随拿随用”。所以 js 预处理工具最主要的工作就是帮助解决 js 的模块问题。而 css 预处理工具则很好理解,就是把 sass,less 或者 stylus 代码翻译、合并成 css 代码。

资源管理工具则是帮我们管理前端所需的各种资源文件(比如 css、js、图片、字体等等),便于我们引用。目前常用的解决方法是将他们直接编码进 js 代码中,然后像引用 js 模块一样引用它们。这可比手写各种 url 方便多了。

正如标题所说,我们将采用 Webpack,因为它具备上面所说的所有功能。此外还支持代码热替换,使修改代码后不用刷新页面也能在浏览器中立即看到效果。

详解如何从零开始搭建Express+Vue开发环境

2. 为后端选择合适的预处理工具

后端面对的都是 js 代码,不需要前端那样的资源管理工具,另外, Node 强迫你使用至少一种模块管理方案(CommonJS 或 ES6 的 import),也不用考虑代码的依赖问题。

所以后端要简单许多,唯一需要考虑的基本上就剩下如何将 ES6 转译成 ES5 了(如果你打算使用 ES6 的话)。目前常用的做法是使用 Babel,你可以用 Babel 命令行工具独立执行编译过程,也可以配置 Babel register 实现代码运行时动态翻译,这对于开发场景而言无疑是最方便的。所以我们选择后一种方式。

3. 为整个项目选择合适的流程控制工具

流程控制工具是为了帮助我们管理诸如代码检查、编译、压缩、移动、部署这些任务的,原本我们是通过手敲命令(或者高级一点写个脚本)的方式做,有了流程控制工具以后,只需要提供配置文件和少量代码就可以完成。

目前最流行的解决方案是 gulp。不过,由于我们这里要搭建的是开发环境,没有移动代码、压缩、部署等需求,所以不需要功能强大的 gulp。我们只要用 nodemon 这个工具监听代码变动然后适时重启 server就够了。

详解如何从零开始搭建Express+Vue开发环境

正式开始搭建

1. 利用 Express 脚手架快速搭建应用

使用 Express 提供的脚手架工具(Express application generator)可以在 1s 之内搭建出最基本的应用。

如果你以前还没试过,首先执行下面的命令安装

npm install express-generator -g

然后执行以下命令生成代码,命令执行过程中需要输入一些参数。

express <myapp>

完成后的文件结构是这样的

.
├── app.js
├── bin
│  └── www
├── package.json
├── public
│  ├── images
│  ├── javascripts
│  └── stylesheets
│    └── style.css
├── routes
│  ├── index.js
│  └── users.js
└── views
  ├── error.jade
  ├── index.jade
  └── layout.jade

但是这个文件结构只是后端代码,要想跟前端代码相结合,需要做一些改动。我们计划最终的文件结构应该是这样的

.
├── src
│  ├── client
│  └── server
└── ...

所以需要将上面自动生成的 Express 代码放到 /src/server/ 路径下。

接下来我们要删除一些用不着的东西以及增加一些缺失的东西。

首先,由于我们打算在前端使用 Vue 框架,并由 Vue-Router 管理大部分路由,后端 Express 仅保留少量的 RESTful API 路由,所以后端不需要复杂的路由设置,那么 routes 文件夹下的内容可以简化成一个 routers.js 文件。

然后,我们需要配置好 Babel register,所以需要在项目跟路径下新增两个文件 .babelrc index.js,内容分别为:

/.babelrc

{
 "presets": ["es2015"],
}

.babelrc 是 Babel 6.0 必须的文件

/.index.js

require('babel-register')
require('./src/server')

上面两句完成 Bebel 注册,它会爬取所有 require import 方式依赖的模块并把它们翻译成 ES5。

自动生成的代码里有个 www 文件,他是 Express 应用的入口文件,我们把它放在 server 路径下并改名为 index.js 以便让上面配置的 Babel register 能正确找到它。

为什么要改名为 index.js ?这是因为 require('./src/server') 在默认情况下会去找 ./src/server/index.js,如果你想用别的名字,那就记得将 Babel register 的配置文件里改为 require(./src/<your entry file>

好了,现在后端的事情先暂时告一段落,接下来看看前端。

2. 利用 Vue 脚手架快速搭建应用

同样地,推荐使用 Vue 自带的template 工具,在 1s 内生成基本代码。

虽然利用这个工具生成的代码的后端就是基于 Express 的,但是后端部分的代码结构太简单,不适合做后续开发。所以建议这里先将 Vue 生成的代码放在另外一个地方,然后按需移动到前面用 Express 生成的代码文件夹里。

首先安装 template 工具

npm install -g vue-cli

然后执行命令生成代码。命令执行过程中需要输入一些参数

vue init webpack <my-project>

生成的代码结构是这样的

.
├── build
│  ├── dev-server.js     # development server script
│  ├── karma.conf.js     # unit testing config
│  ├── webpack.base.conf.js # shared base webpack config
│  ├── webpack.dev.conf.js  # development webpack config
│  ├── webpack.prod.conf.js # production webpack config
│  └── ...
├── src
│  ├── main.js        # app entry file
│  ├── App.vue        # main app component
│  ├── components      # ui components
│  │  └── ...
│  └── assets        # module assets (processed by webpack)
│    └── ...
├── static          # pure static assets (directly copied)
├── dist           # built files ready for deploy
├── test
│  └── unit         # unit tests
│    ├── index.js     # unit test entry file
│    └── ...
├── .babelrc         # babel config
├── .eslintrc.js       # eslint config
├── index.html        # main html file
└── package.json       # build scripts and dependencies

我们发现这里也有一个 .babelrc,内容跟之前自己创建的基本一致,可以忽略它。此外,它还提供了 .eslintrc.js,是为了配合 eslint 检查代码是否符合规范的。这里面的内容很简单,想要偷懒就直接拿过来,觉得定制的规则不太符合自己的习惯的可以另外配置。

然后看到 build 路径下有 3 个 webpack 有关的配置文件,因为我们是要搭建开发环境,所以挑里面的 webpack.base.conf.js 和 webpack.dev.conf.js 就可以,建议把内容合并到一个 webpack.conf.js 文件里,放在项目的根目录下。

之后,基本上就是把 src 目录移动到之前用 Express 创建的 /src/client/,我习惯将所有 js 的入口文件都改为 index.js 所以,这里也可以将 src/client/main.js 改名为 src/client/index.js。

其他的文件先忽略不管。

到这里,前端部分的代码也基本整理完毕了。

3. 配置 Webpack

我们计划让 Webpack 将前端文件打包成一个 build.js 文件,然后放在 /src/server/public/javascripts 中供 jade 模板使用。所以设置好 webpack 的路径部分(其他的保留原来的就好):

{
 ...
 entry: path.join(__dirname, 'src/client/index.js'),
  output: {
   path: path.join(__dirname, 'src/server/public/javascripts/'),
   publicPath: '/javascripts/',
   filename: 'build.js'
  },
 ...
}

至于如何启动 Webpack,你可以选择单独用一个 shell 窗口运行它,也可以以 Express 中间件的形式提供代理。采用后一种方式,webpack 并不会把打包好的代码生成在磁盘上,而是保留在内存里。我们选择后一种方式,因为更方便。

只应该在开发环境中以 Express 中间件的形式部署 Webpack

所以需要修改 /src/server/index.js,关键是增加这几句

import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import config from '../../webpack.config'

const compiler = webpack(config)

app.use(webpackDevMiddleware(compiler, {
 publicPath: config.output.publicPath,
 stats: { colors: true },
}))

app.use(webpackHotMiddleware(compiler))

这样每次启动 Express 后,Webpack 中间件会拦截 config.output.publicPath 地址的请求并返回正确的结果,同时,如果被 Webpack 监听的文件发生变动,会立即通知前端产生相应变化。

4. 配置 Nodemon

之前提到过,计划用 Nodemon 启动 server 并监听代码变动。而 Nodemon 默认会监听除了 .git 和 node_modules 路径外的所有 js 代码,因为我们已经有 Webpack 监听前端代码了,所以得做相关配置让 Nodemon 只监听某一块代码。

在项目根路径下新增文件 nodemon.json,内容为

{
 "verbose": true,
 "ignore": ["src/server/public/"],
 "events": {
  "restart": "osascript -e 'display notification \"App restarted due to:\n'$FILENAME'\" with title \"nodemon\"'"
 },
 "watch": ["src/server/"],
 "env": {
  "NODE_ENV": "development"
 },
 "ext": "js jade"
}

其中,将 verbose 设置为 true 将打印更丰富的日志信息,对开发很有帮助。

我们选择让 Nodemon 监听 src/server/ 目录,并忽略 src/server/public 目录,因为那里是前端 webpack 生成打包文件的地方。注意我们是以 Express 中间件的形式使用 Webpack,并不会在磁盘上真的产生文件,所以这个 ignore 规则其实可以省略。

别忘了在文件扩展名中增加 jade 类型,因为 Express 使用的是 jade 模板。

5. 配置 package.json

首先在 script 中增加一个命令,用来启动整个应用

{
 ...
 "scripts": {
  "dev": "nodemon index.js"
 },
 ...
}

这样,只需要运行 npm run dev 这一个命令就可以启动 server 同时进行开发了。

完整的代码已经上传 Github,点击访问

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
文本加密解密
Jun 23 Javascript
js 数组克隆方法 小结
Mar 20 Javascript
javascript函数重载解决方案分享
Feb 19 Javascript
Jquery+Ajax+xml实现中国地区选择三级联动菜单效果(推荐)
Jun 09 jQuery
angular指令笔记ng-options的使用方法
Sep 18 Javascript
vue中的router-view组件的使用教程
Oct 23 Javascript
jQuery简单实现根据日期计算星期几的方法
Jan 09 jQuery
使用webpack搭建vue项目及注意事项
Jun 10 Javascript
策略模式实现 Vue 动态表单验证的方法
Sep 16 Javascript
JavaScript之Blob对象类型的具体使用方法
Nov 29 Javascript
如何在vue 中引入使用jquery
Nov 10 jQuery
AJAX学习笔记
May 18 Javascript
微信小程序自定义组件之可清除的input组件
Jul 17 #Javascript
微信小程序倒计时功能实例代码
Jul 17 #Javascript
详解vue+webpack+express中间件接口使用
Jul 17 #Javascript
微信小程序实现默认第一个选中变色效果
Jul 17 #Javascript
Vue2.X 通过AJAX动态更新数据
Jul 17 #Javascript
浅谈Angularjs中不同类型的双向数据绑定
Jul 16 #Javascript
微信小程序实现循环动画效果
Jul 16 #Javascript
You might like
PHP 和 HTML
2006/10/09 PHP
深入解析PHP中的(伪)多线程与多进程
2013/07/01 PHP
ci检测是ajax还是页面post提交数据的方法
2014/11/10 PHP
PHP Imagick完美实现图片裁切、生成缩略图、添加水印
2016/02/22 PHP
js打印纸函数代码(递归)
2010/06/18 Javascript
javascript实现json页面分页实例代码
2014/02/20 Javascript
jquery自定义插件开发之window的实现过程
2016/05/06 Javascript
用vue封装插件并发布到npm的方法步骤
2017/10/18 Javascript
记React connect的几种写法(小结)
2018/09/18 Javascript
elementUI Tree 树形控件的官方使用文档
2019/04/25 Javascript
详解js location.href和window.open的几种用法和区别
2019/12/02 Javascript
js中forEach,for in,for of循环的用法示例小结
2020/03/14 Javascript
微信小程序实现点赞业务
2021/02/10 Javascript
[34:39]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#1COL VS EG第二局
2016/03/05 DOTA
python的描述符(descriptor)、装饰器(property)造成的一个无限递归问题分享
2014/07/09 Python
探寻python多线程ctrl+c退出问题解决方案
2014/10/23 Python
浅析Python中的多条件排序实现
2016/06/07 Python
解决sublime+python3无法输出中文的问题
2018/12/12 Python
pycharm无法导入本地模块的解决方式
2020/02/12 Python
python开发前景如何
2020/06/11 Python
CSS3教程(8):CSS3透明度指南
2009/04/02 HTML / CSS
详解基于canvas的视频遮罩插件
2018/01/04 HTML / CSS
ProBikeKit美国官网:自行车套件,跑步和铁人三项套件
2016/10/13 全球购物
日本小田急百货官网:Odakyu
2018/07/19 全球购物
Ellesse英国官网:意大利高级运动品牌
2019/07/23 全球购物
远东集团网络工程师面试题
2014/10/20 面试题
销售行业个人求职自荐信
2013/09/25 职场文书
幼儿园老师寄语
2014/04/03 职场文书
我的教育故事演讲稿
2014/05/04 职场文书
家长建议怎么写
2014/05/15 职场文书
党员民主生活会整改措施
2014/09/26 职场文书
会计试用期工作总结2015
2015/05/28 职场文书
教务处教学工作总结
2015/08/10 职场文书
MATLAB 全景图切割及盒图显示的实现步骤
2021/05/14 Python
CSS布局之浮动(float)和定位(position)属性的区别
2021/09/25 HTML / CSS
Python 的 sum() Pythonic 的求和方法详细
2021/10/16 Python