Skip to content

Commit 89bf81b

Browse files
committed
milestone
1 parent 7891149 commit 89bf81b

File tree

9 files changed

+281
-64
lines changed

9 files changed

+281
-64
lines changed

.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["env"]
3+
}

.gitignore

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1 @@
1-
# Logs
2-
logs
3-
*.log
4-
npm-debug.log*
5-
yarn-debug.log*
6-
yarn-error.log*
7-
8-
# Runtime data
9-
pids
10-
*.pid
11-
*.seed
12-
*.pid.lock
13-
14-
# Directory for instrumented libs generated by jscoverage/JSCover
15-
lib-cov
16-
17-
# Coverage directory used by tools like istanbul
18-
coverage
19-
20-
# nyc test coverage
21-
.nyc_output
22-
23-
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24-
.grunt
25-
26-
# Bower dependency directory (https://bower.io/)
27-
bower_components
28-
29-
# node-waf configuration
30-
.lock-wscript
31-
32-
# Compiled binary addons (https://nodejs.org/api/addons.html)
33-
build/Release
34-
35-
# Dependency directories
36-
node_modules/
37-
jspm_packages/
38-
39-
# TypeScript v1 declaration files
40-
typings/
41-
42-
# Optional npm cache directory
43-
.npm
44-
45-
# Optional eslint cache
46-
.eslintcache
47-
48-
# Optional REPL history
49-
.node_repl_history
50-
51-
# Output of 'npm pack'
52-
*.tgz
53-
54-
# Yarn Integrity file
55-
.yarn-integrity
56-
57-
# dotenv environment variables file
58-
.env
59-
60-
# next.js build output
61-
.next
1+
node_modules

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2018 Stefan
3+
Copyright (c) 2018 Jordan Wang
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,84 @@
1-
# deploy-server-webpack-plugin
2-
A plugin that deploys bundles to server
1+
# Introduction
2+
A plugin that deploys webpack bundles to server. It's useful when server ftp/sftp is forbidden or accessing server need pin + dynamic token.
3+
4+
# Install
5+
```
6+
npm i deploy-server-webpack-plugin -D
7+
```
8+
9+
# Usage
10+
11+
**Client config**
12+
13+
You need config your webpack conf file like this:
14+
15+
```js
16+
const DeployServerPlugin = require('deploy-server-webpack-plugin');
17+
18+
module.exports = {
19+
// ...
20+
plugins: [
21+
// ...
22+
new DeployServerPlugin({
23+
receiver: 'http://1.23.45.678:9999/receiver',
24+
mapping: { // Object type
25+
from: path.resolve(__dirname, '../dist'), // absolute path
26+
dest: '/data/front'
27+
}
28+
})
29+
]
30+
};
31+
```
32+
or
33+
34+
```js
35+
const DeployServerPlugin = require('deploy-server-webpack-plugin')
36+
37+
module.exports = {
38+
// ...
39+
plugins: [
40+
// ...
41+
new DeployServerPlugin({
42+
receiver: 'http://1.23.45.678:9999/receiver',
43+
mapping: [ // Array type
44+
{
45+
from: path.resolve(__dirname, '../dist/static'), // absolute path
46+
dest: '/data/public/static',
47+
},
48+
{
49+
from: path.resolve(__dirname, '../dist/index.tpl'), // absolute path
50+
dest: '/data/views/index.tpl',
51+
},
52+
// ...
53+
],
54+
token: '123456789'
55+
})
56+
]
57+
};
58+
```
59+
60+
**Server Config**
61+
62+
Please copy ./server folder to you remote server somewhere, init the project and start it.
63+
64+
```
65+
npm i
66+
npm run start
67+
```
68+
Next config your nginx/apache to allow your node service can be accessed.
69+
70+
Try to visit "@your host/receiver" in browser, when you see "Method Not Allowed", it means node server started success, but 'GET' method is not allowed because we only config "POST" router to upload files.
71+
72+
# Options
73+
74+
|Name|Type|Required|Description|
75+
|:--:|:--:|:-----:|:----------|
76+
|receiver|String|true|server url used to receive files|
77+
|mapping|Object, Array|true|files will be copied from 'form' to 'dest'|
78+
|token|String|false|for security if needed|
79+
80+
# Others
81+
Sometimes bundle files are too big and uploading appears "504 Gateay Time-out" error, enlarge client_max_body_size value in nginx.conf may solve this problem:
82+
```
83+
client_max_body_size: 10M; #default 1M
84+
```

dist/index.js

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "deploy-server-webpack-plugin",
3+
"version": "0.0.1",
4+
"description": "A plugin that deploys wepack bundles to server",
5+
"main": "dist/index.js",
6+
"scripts": {
7+
"babel": "babel ./src -d ./dist --compact"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/mingmingwon/deploy-server-webpack-plugin.git"
12+
},
13+
"keywords": [
14+
"deploy server",
15+
"webpack plugin"
16+
],
17+
"author": "Jordan Wang",
18+
"license": "MIT",
19+
"bugs": {
20+
"url": "https://github.com/mingmingwon/deploy-server-webpack-plugin/issues"
21+
},
22+
"homepage": "https://github.com/mingmingwon/deploy-server-webpack-plugin#readme",
23+
"dependencies": {
24+
"chalk": "^2.4.1",
25+
"request": "^2.87.0"
26+
},
27+
"devDependencies": {
28+
"babel-cli": "^6.26.0",
29+
"babel-preset-env": "^1.7.0"
30+
}
31+
}

server/app.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const Koa = require('koa');
2+
const koaBody = require('koa-body');
3+
const Router = require('koa-router');
4+
const fse = require('fs-extra');
5+
6+
const router = new Router();
7+
router.post('/receiver', koaBody({
8+
multipart: true
9+
}), async (ctx, next) => {
10+
const { files, body: { dest, token } } = ctx.request;
11+
12+
// deal with "token" here if needed
13+
14+
for (let key in files) {
15+
const file = files[key];
16+
try {
17+
await fse.copy(file.path, dest);
18+
console.log(new Date().toLocaleString(), 'success', dest);
19+
ctx.body = '0';
20+
} catch (err) {
21+
console.log(new Date().toLocaleString(), 'failed', dest, err);
22+
ctx.status = 500;
23+
// don't tell client error detail
24+
ctx.body = 'Internal Server Error';
25+
}
26+
}
27+
});
28+
29+
const app = new Koa();
30+
app.use(router.routes());
31+
app.use(router.allowedMethods());
32+
33+
app.listen(3000, () => {
34+
console.log('server is ready');
35+
});

server/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "receiver",
3+
"version": "0.0.1",
4+
"description": "file receiver",
5+
"main": "app.js",
6+
"scripts": {
7+
"start": "pm2 start app.js",
8+
"stop": "pm2 stop app.js"
9+
},
10+
"author": "Jordan Wang",
11+
"license": "MIT",
12+
"dependencies": {
13+
"fs-extra": "^6.0.1",
14+
"koa": "^2.5.2",
15+
"koa-body": "^4.0.4",
16+
"koa-router": "^7.4.0",
17+
"pm2": "^3.0.0"
18+
}
19+
}

src/index.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const chalk = require('chalk');
4+
const request = require('request');
5+
6+
module.exports = class DeployServerWebpackPlugin {
7+
constructor(config = {}) {
8+
this.config = config;
9+
}
10+
11+
apply(compiler) {
12+
compiler.plugin('after-emit', (compilation, callback) => {
13+
this.validConfig(compilation);
14+
this.deployHandler(callback);
15+
});
16+
}
17+
18+
validConfig(compilation) {
19+
const { receiver, token = '' } = this.config;
20+
let { mapping } = this.config;
21+
22+
if (!receiver) {
23+
this.error('Missing param: receiver');
24+
}
25+
if (!mapping) {
26+
this.error('Missing param: mapping');
27+
}
28+
29+
const mappingType = Object.prototype.toString.call(mapping);
30+
if (mappingType === '[object Object]') {
31+
mapping = [mapping];
32+
} else if (mappingType === '[object Array]') {
33+
// do nothing
34+
} else {
35+
this.error('Invalid param: mapping');
36+
}
37+
38+
const assets = compilation.assets;
39+
const avalAssets = {};
40+
mapping.map((item, index) => {
41+
for (let key in assets) {
42+
const asset = assets[key];
43+
const assetPath = asset.existsAt;
44+
const from = item.from;
45+
// limit "src" path within compiled files
46+
if (assetPath.startsWith(from)) {
47+
if (!avalAssets[from]) {
48+
avalAssets[from] = [assetPath];
49+
continue;
50+
}
51+
avalAssets[from].push(assetPath);
52+
}
53+
}
54+
});
55+
56+
const avalKeys = Object.keys(avalAssets);
57+
if (!avalKeys.length) {
58+
this.error('No available mapping files');
59+
}
60+
61+
this.receiver = receiver;
62+
this.mapping = mapping;
63+
this.token = token;
64+
this.avalKeys = avalKeys;
65+
this.avalAssets = avalAssets;
66+
}
67+
68+
deployHandler(callback) {
69+
const formData = {};
70+
this.avalKeys.map((item, index) => {
71+
this.avalAssets[item].map(from => {
72+
// compatible with windows
73+
const dest = (this.mapping[index].to + from.replace(item, '')).replace(/\\/g, '/');
74+
this.deploy({
75+
dest,
76+
token: this.token,
77+
file: fs.createReadStream(from)
78+
});
79+
});
80+
});
81+
82+
callback();
83+
}
84+
85+
deploy(formData) {
86+
request.post({
87+
url: this.receiver,
88+
formData
89+
}, (err, { statusCode } = {}, body) => {
90+
const time = new Date().toLocaleTimeString();
91+
if (!err && 200 === statusCode) {
92+
console.log(chalk.green(`[${time}] [success] => ${formData.dest}`));
93+
return;
94+
}
95+
console.log(chalk.yellow(`[${time}] [failed] => ${formData.dest} ${body}`));
96+
});
97+
}
98+
99+
error(err) {
100+
console.log(`\n${chalk.yellow('[deploy-server-webpack-plugin] ' + err)}`);
101+
process.exit();
102+
}
103+
};

0 commit comments

Comments
 (0)