开发环境:
- 系统:Windows 10 64位教育版
- nodejs: v14.15.5
- 后端:express 4.17.1
- 前端:vue 2.5.2
1. 准备环境。
常规操作安装express 项目生成器,并安装依赖库,启动项目:
npm install express-generator -g
express -e demo
cd demo
npm install
npm start
####安装热更新,方便部署
$ npm install -g supervisor
启动项目
$ supervisor bin/www
后端项目搭建完成。接下来新建路由:
在 demo/routes目录下新建 api.js
粘贴如下内容:
var express = require("express");
var router = express.Router();
/* POST login page. */
router.post("/login", function (req, res, next) {
//获取请求传递过来的数据
var currentData = req.body.params;
console.log("currentdata:", currentData);
//模拟数据库查询判断,设置返回数据str
if (currentData.username == "1" && currentData.password == "1") {
var str = {
result: {
username: currentData.username,
},
tip: "登录成功!",
code: 1,
};
} else {
var str = { result: {}, tip: "用户名或密码错误!", code: 0 };
}
res.writeHead(200, {
"Content-Type": "text/plain",
charset: "utf-8",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "PUT,POST,GET,DELETE,OPTIONS",
}); //可以解决跨域的请求
str = JSON.stringify(str);
//打印要返回的数据str
console.log("resData: " + str);
res.end(str);
});
module.exports = router;
用于处理前端登录请求。之后,在demo/app.js 中添加路由规则:
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
var apiRouter = require("./routes/api");
var app = express();
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");
// 自定义跨域中间件
var allowCors = function (req, res, next) {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Credentials", "true");
next();
};
app.use(allowCors); //使用跨域中间件
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/api", apiRouter); // 登录处理
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app;
保存即可。2. vue 前端项目搭建
先安装脚手架:
之后会提示:npm install -g vue-cli
vue init webpack test
? Project name test
? Project description A Vue.js project
? Author neuhxy
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recommended) npm
vue-cli · Generated "test".
修改前端页面的 App.vue,修改后内容如下:
<template>
<div id="app">
<!-- <img src="./assets/logo.png" /> -->
<h3>化检验数据录入小工具</h3>
<input type="text" name="username" v-model="username" /> <br /><br />
<input type="password" name="password" v-model="password" /><br /><br />
<button @click="login">登录</button>
<br />
<p>{{ msg }}</p>
<!-- <router-view /> -->
</div>
</template>
<script>
import axios from "axios";
export default {
name: "App",
data() {
return {
username: "",
password: "",
msg: "",
};
},
methods: {
login: function () {
axios
.post("http://localhost:3000/api/login", {
params: {
username: this.username,
password: this.password,
},
})
.then((res) => {
//data属性名称是固定的,用于获取后台响应的数据
console.log(res.data);
this.msg = res.data.tip;
});
},
},
watch: {
username: function (username) {
this.username = username;
},
password: function (password) {
this.password = password;
},
},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
需要安装 axios 用于后台数据的交互:yarn add axios
大概需要几分钟,安装之后,打开 lcoalhost:8080, 输入用户名密码,如提示跨域错误,前端test/config/index.js 的proxyTable添加后台服务器地址及端口,完整index.js代码如下:
"use strict";
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require("path");
module.exports = {
dev: {
// Paths
assetsSubDirectory: "static",
assetsPublicPath: "/",
proxyTable: {
"/api": {
target: "http://localhost:3000",
changeOrigin: true,
pathRewrite: {
"^/api": ""
}
}
},
// 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",
// 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
index: path.resolve(__dirname, "../dist/index.html"),
// Paths
assetsRoot: path.resolve(__dirname, "../dist"),
assetsSubDirectory: "static",
assetsPublicPath: "/",
/**
* Source Maps
*/
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
productionGzip: false,
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
}
};
接下来请修改后台 demo/app.js ,添加 express 允许跨域代码(如直接粘贴上面的代码,请忽略此操作):
// 自定义跨域中间件
var allowCors = function (req, res, next) {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Credentials", "true");
next();
};
app.use(allowCors); //使用跨域中间件
输入用户名、密码都是1,再次点击登录,OK了。
3. docker 打包
先打包后台:
在(express后台) demo 根目录创建Dockerfile,写入如下内容:
# 常规配置:940Mb左右
# FROM node
# COPY . /app
# WORKDIR /app
# RUN npm install
# EXPOSE 3000
# CMD npm start
# 最小压缩配置:62Mb
FROM alpine AS builder
WORKDIR /home/www/node
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add --no-cache --update nodejs nodejs-npm
COPY package.json package-lock.json ./
RUN npm install --production
FROM alpine
WORKDIR /home/www/express
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add --no-cache --update nodejs nodejs-npm
COPY --from=builder /home/www/node/node_modules ./node_modules
COPY . .
EXPOSE 3000
ENTRYPOINT ["npm", "run"]
CMD ["start"]
然后执行:docker build -t nodeserver .运行:docker run -p 3000:3000 -d --name nodeserver nodeserver
打开浏览器:localhost:3000可以看到启动成功。
然后配置前端:
# 常规配置,配置完大约132Mb
# FROM nginx
# COPY dist/ /usr/share/nginx/html/
# COPY nginx/default.conf /etc/nginx/conf.d/default.conf
# 最小压缩配置
# 拉取最小体积的node环境容器, 并安装cnpm (加快容器构建速度,npm比较慢)
FROM node:lts-alpine as build-stage
# 进入容器的app目录, 然后拷贝当前目录(根目录)的所有文件到容器的当前目录中(/app)
WORKDIR /
COPY . .
# 删除vue环境配置文件(主要想通过容器的环境变量来达到不同的环境切换,以及为了部署到阿里云的容器服务或华为云的容器服务时, 通过配置项来配置相关的环境变量, 如果不需要可自行删除以下这句代码)
# RUN rm -f .env.*
# ENV VUE_APP_TEST_VALUE="My test Value"
#在容器内build
RUN npm install && npm run build
# production stage
# 最后通过nginx部署build出来的文件(/dist)
FROM nginx:stable-alpine as production-stage
COPY dist/ /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
执行:docker build -t vtest .启动命令:docker run -p 80:80 -d --name vueApp vtest
这样,用两个docker包就可以搞定了。