LI WENHAO

init rf-blog project

init rf-blog db config
init rf-blog vue config
init rf-blog node config
create dev-admin\dev-client
Showing 60 changed files with 603 additions and 0 deletions
{
"presets": [
"es2015",
[
"env",
{
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}
],
"stage-2"
],
"plugins": ["transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"]
}
}
}
MIT License
Copyright (c) 2021 rf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"use strict";
process.env.NODE_ENV = "production";
const path = require("path");
const webpack = require("webpack");
const config = require("./webpack.prod.conf");
const compiler = webpack(config);
// 以包的形式包装rm -rf命令,删除文件夹
const rm = require("rimraf");
// 美化node控制台进度
const ora = require("ora");
const spinner = ora({
text: "building for production loading...",
color: "yellow",
spinner: { interval: 80, frames: ["-", "+", "-"] },
});
// 开启loading动画
spinner.start();
// 美化控制台输出
const chalk = require("chalk");
const isAdmin = process.env.NODE_ENV_TYPE === "admin";
// 打包前先删除之前可能已打包过的文件
const rmFile = path.resolve(
__dirname,
`../puclic/${isAdmin ? "admin" : "client"}`
);
rm(rmFile, (rmErr) => {
if (rmErr) throw rmErr;
compiler.run((err, stats) => {
spinner.stop();
if (err) {
throw err;
}
if (stats.hasErrors()) {
console.log(chalk.redBright("Build failed with errors.\n"));
process.exit(1);
}
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
}) + "\n\n"
);
console.log(chalk.greenBright("Build completed with success.\n"));
compiler.close((closeErr) => {
if (closeErr) {
console.log(
chalk.redBright(
`compiler close failed with message ${closeErr.message}`
)
);
}
});
});
});
module.exports = {
admin: {
dev: {
env: "development",
publicPath: "/",
host: "localhost",
port: "8090",
assetsSubDirectory: "static",
devtoolType: "eval-cheap-module-source-map",
proxyTable: {
"/admin_api": {
target: "http://localhost:3000/admin_api/",
changeOrigin: true,
pathRewrite: {
"^/admin_api": "/",
},
},
},
},
build: {
env: "production",
publicPath: "./", // html引用资源路径
assetsPath: "static", // 静态资源目录
assetsSubDirectory: "static", // html资源存放目录
devtoolType: "source-map", // 代码位置信息
},
},
client: {
dev: {
env: "development",
publicPath: "/",
host: "localhost",
port: "8080",
assetsSubDirectory: "static",
devtoolType: "eval-cheap-module-source-map",
proxyTable: {
"/client_api": {
target: "http://localhost:3000/client_api/",
changeOrigin: true,
pathRewrite: {
"^/client_api": "/",
},
},
},
},
build: {
env: "production",
publicPath: "./",
assetsPath: "static",
assetsSubDirectory: "static",
devtoolType: "source-map",
},
},
};
"use strict";
const path = require("path");
const VueLoaderPlugin = require("vue-loader/lib/plugin");
// 以link标签形式,抽离出css
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const isAdmin = process.env.NODE_ENV_TYPE === "admin";
const isProd = process.env.NODE_ENV === "prod";
const prodConf = isAdmin
? require("./config").admin.build
: require("./config").client.build;
// 拼接路径
const resolve = (dir) => {
return path.join(__dirname, "..", dir);
};
// 资源路径
const assetsPath = (dir) => {
return path.posix.join(prodConf.assetsPath, dir);
};
module.exports = {
entry: {
app: [
isAdmin
? resolve("code/admin/src/main.js")
: resolve("code/client/src/main.js"),
"babel-polyfill",
],
},
// 配置模块如何被解析
resolve: {
//自动解析文件扩展名(补全文件后缀)(从左->右)
extensions: [".js", ".vue", ".json"],
// 配置别名映射
alias: {
vue$: "vue/dist/vue.esm.js",
src: isAdmin ? resolve("code/admin/src") : resolve("code/client/src"),
components: isAdmin
? resolve("code/admin/src/components")
: resolve("code/client/src/components"),
style: isAdmin
? resolve("code/admin/src/styles")
: resolve("code/client/src/style"),
views: isAdmin
? resolve("code/admin/src/views")
: resolve("code/client/src/views"),
store: isAdmin
? resolve("code/admin/src/store")
: resolve("code/client/src/store"),
api: isAdmin
? resolve("code/admin/src/api")
: resolve("code/client/src/api"),
utils: isAdmin
? resolve("code/admin/src/utils")
: resolve("code/client/src/utils"),
},
},
plugins: [
// 引用vue-loader时必须确保引入该plugin
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: assetsPath("css/[name].[chunkhash].css"),
chunkFilename: assetsPath("css/[name].[chunkhash].css"),
}),
],
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
include: isAdmin
? resolve("code/admin/src")
: resolve("code/client/src"),
},
{
test: /\.vue$/,
loader: "vue-loader",
include: isAdmin
? resolve("code/admin/src")
: resolve("code/client/src"),
},
{
test: /\.css$/,
use: [
!isProd
? { loader: "vue-style-loader" }
: MiniCssExtractPlugin.loader,
{ loader: "css-loader" },
],
},
// 开发环境使用vue-style-loader可以重载样式模块
{
test: /\.less$/,
use: [
!isProd
? { loader: "vue-style-loader" }
: MiniCssExtractPlugin.loader,
{ loader: "css-loader" },
{ loader: "less-loader" },
{
loader: "style-resources-loader",
options: {
patterns: path.resolve(__dirname, "../styles/theme.less"),
},
},
],
},
{
test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
loader: "url-loader",
options: {
limit: 10000,
name: assetsPath("img/[name].[hash:7].[ext]"),
},
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: "url-loader",
options: {
limit: 10000,
name: assetsPath("fonts/[name].[hash:7].[ext]"),
},
},
],
},
};
"use strict";
const webpack = require("webpack");
// 合并配置
const { merge } = require("webpack-merge");
// 配置需打包的html入口信息,并创建一个新的html文件
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 编译提示
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin");
// 系统桌面通知
const notifier = require("node-notifier");
const isAdmin = process.env.NODE_ENV_TYPE === "admin";
// 开发环境配置参数
const devConf = isAdmin
? require("./config").admin.dev
: require("./config").client.dev;
const baseConf = require("./webpack.base.conf");
const dev = merge(baseConf, {
mode: "development",
output: {
filename: "[name]-[hash].js",
// html引用资源路径,在dev-server中,引用的是内存中文件
publicPath: devConf.publicPath,
},
module: {},
// 生成sourceMap(方便调试)
devtool: devConf.devtoolType,
// 启动一个本地服务器,可进行本地开发
devServer: {
hot: true, // 热加载
open: true, // 自动打开浏览器
historyApiFallback: true, // 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
host: devConf.host,
port: devConf.port,
proxy: devConf.proxyTable, // 配置反向代理解决跨域
compress: true, // 压缩代码
client: {
// 在浏览器上全屏显示编译的errors
overlay: {
errors: true,
warnings: false,
},
},
},
watchOptions: {
ignored: ["**/.#*.vue", "node_modules/**"],
},
plugins: [
// 开启HMR(热替换功能,替换更新部分,不重载页面!)
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
filename: "index.html",
template: isAdmin ? "code/admin/index.html" : "code/client/index.html",
inject: true,
}),
// 编译提示
new FriendlyErrorsPlugin({
// 编译成功
compilationSuccessInfo: {
messages: [
`Your application is running here: http://${devConf.host}:${devConf.port}`,
],
},
// 编译出错
onErrors: (severity, errors) => {
if (severity !== "error") {
return;
}
const error = errors[0];
// 编译出错时,系统右下角弹出错误提示
notifier.notify({
title: "Webpack error",
message: severity + ": " + error.name,
subtitle: error.file || "",
});
},
clearConsole: true, // 每次编译之间清除控制台
}),
],
});
module.exports = dev;
"use strict";
const path = require("path");
const webpack = require("webpack");
// 合并配置
const { merge } = require("webpack-merge");
// 配置需打包的html入口信息,并创建一个新的html文件
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 压缩js
const TerserPlugin = require("terser-webpack-plugin");
// 压缩css
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 开启Gzip压缩,nginx需要配置
const CompressionPlugin = require("compression-webpack-plugin");
const isAdmin = process.env.NODE_ENV_TYPE === "admin";
// 生产环境配置参数
const prodConf = isAdmin
? require("./config").admin.build
: require("./config").client.build;
const baseConf = require("./webpack.base.conf");
// 资源路径
const assetsPath = (dir) => {
return path.posix.join(prodConf.assetsSubDirectory, dir);
};
const prod = merge({}, baseConf, {
mode: "production",
output: {
// build后所有文件存放的位置
path: path.resolve(__dirname, `../public/${isAdmin ? "admin" : "client"}`),
// html引用资源路径,可在此配置cdn引用地址
publicPath: prodConf.publicPath,
filename: assetsPath("js/[name].[chunkhash].js"),
// 用于打包require.ensure(代码分割)方法中引入的模块
chunkFilename: assetsPath("js/[name].[chunkhash].js"),
},
module: {},
optimization: {
moduleIds: "deterministic", // 被哈希转化成的小位数值模块名
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
format: {
comments: false, // 删除注释
},
},
}),
new CssMinimizerPlugin({
parallel: true,
minimizerOptions: {
preset: [
"default",
{
discardComments: { removeAll: true }, // 删除注释
},
],
},
}),
],
splitChunks: {
chunks: "all",
minSize: 30000, // 形成一个新代码块最小的体积
maxAsyncRequests: 5, // 按需加载时候最大的并行请求数
maxInitialRequests: 3, // 最大初始化请求数
automaticNameDelimiter: "~", // 打包分割符
cacheGroups: {
// 打包第三方库
vendors: {
name: `chunk-vendors`,
test: /[/]node_modules[/]/,
priority: -10, // 优先级
chunks: "initial",
},
// 打包其余的的公共代码
common: {
name: `chunk-common`,
minChunks: 2, // 引入两次及以上被打包
priority: -20,
chunks: "initial",
reuseExistingChunk: true,
},
},
},
},
plugins: [
// 作用域提升,提升代码在浏览器执行速度
new webpack.optimize.ModuleConcatenationPlugin(),
new HtmlWebpackPlugin({
filename: "index.html",
template: isAdmin ? "code/admin/index.html" : "code/client/index.html",
inject: true,
minify: {
removeComments: true, // 删除html注释
collapseWhitespace: true, // 去除空格
removeRedundantAttributes: true, // 删除多余的属性
},
}),
new CompressionPlugin({
filename: "[path][base].gz",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
],
});
// 项目打包后,进行性能分析
if (process.env.analyz_npm_config_report) {
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
prod.plugins.push(new BundleAnalyzerPlugin());
}
module.exports = prod;
{
"name": "rf-blog",
"version": "1.0.0",
"author": "rf",
"description": "A blog website sharing front-end technology",
"keywords": [
"vue",
"node",
"koa",
"mongodb"
],
"main": "index.js",
"scripts": {
"dev:admin": "cross-env NODE_ENV_TYPE=admin webpack-dev-server --config build/webpack.dev.conf.js",
"dev:client": "cross-env NODE_ENV_TYPE=client webpack-dev-server --config build/webpack.dev.conf.js",
"build:admin": "cross-env NODE_ENV_TYPE=admin NODE_ENV=prod node build/build.js",
"build:client": "cross-env NODE_ENV_TYPE=client NODE_ENV=prod node build/build.js",
"analyz:admin": "cross-env analyz_npm_config_report=true npm run build:admin",
"analyz:client": "cross-env analyz_npm_config_report=true npm run build:client",
"server": "cross-env NODE_ENV=development nodemon code/server/index.js",
"start": "pm2 start code/server/index.js",
"stop": "pm2 stop code/server/index.js",
"restart": "pm2 restart code/server/index.js"
},
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"babel-register": "^6.26.0",
"chalk": "^2.3.0",
"compression-webpack-plugin": "^8.0.1",
"cross-env": "^5.1.3",
"css-loader": "^0.28.8",
"css-minimizer-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.6",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^5.3.2",
"less": "^2.7.3",
"less-loader": "^4.0.5",
"mini-css-extract-plugin": "^2.2.0",
"node-notifier": "^5.1.2",
"nodemon": "^1.12.1",
"ora": "^1.3.0",
"postcss-loader": "^2.0.10",
"rimraf": "^2.6.2",
"style-resources-loader": "^1.4.1",
"terser-webpack-plugin": "^5.1.4",
"url-loader": "^0.6.2",
"vue-loader": "^15.7.0",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.5.13",
"webpack": "^5.51.1",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.0.0",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"axios": "^0.17.0",
"babel-polyfill": "^6.26.0",
"busboy": "^0.2.14",
"clipboard": "^2.0.8",
"element-ui": "^2.0.11",
"highlight.js": "^10.7.0",
"ip": "^1.1.5",
"js-md5": "^0.7.3",
"jsonwebtoken": "^8.1.0",
"koa": "^2.4.1",
"koa-bodyparser": "^4.2.0",
"koa-router": "^7.3.0",
"koa-static": "^4.0.2",
"log4js": "^2.4.1",
"marked": "^0.3.12",
"mongoose": "^4.13.9",
"nprogress": "^0.2.0",
"qs": "^6.5.1",
"vue": "^2.5.13",
"vue-color": "^2.8.1",
"vue-lazyload": "^1.3.3",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"
}
}
module.exports = {
plugins: [
require("autoprefixer")({
browsers: ["iOS >= 7", "Android >= 4.1", 'last 5 versions']
})
]
};
No preview for this file type
File mode changed
/**
* 变量样式
*/
@mainColor: #333; // 主颜色
@thinColor: #555; // 描述色
@assistColor: #999; // 辅助色
@warningColor: #ff6c1a; // 提醒色
@errorColor: #fe3438; //错误、禁用色
@highlightColor: #009688; // 高亮色
@thinHighlightColor: #20b2aa; // 高亮浅色
@borderColor: #ededed; // 边框色
@borderBoldColor: #ccc; // 边框辅色
@cuttingLineColor: #f0f0f0; // 分割线色
@backgroundColor: rgba(233, 234, 237, 0.7); // 背景色
@thinBgColor: #f6f6f6; // 背景色
@baseSpH: 24px; // 基础左右间距
@baseSp: 20px; // 基础间距
@min-body-height: calc(~"100vh - 50px"); // 页面最小高度,去除顶部的高度
.ellipsis-line-clamp (@line: 1) {
display: -webkit-box;
text-overflow: ellipsis;
-webkit-line-clamp: @line;
-webkit-box-orient: vertical;
overflow: hidden;
}
This diff could not be displayed because it is too large.