Selaa lähdekoodia

初始提交

master
leiyun 10 kuukautta sitten
commit
fa0344fb0c
40 muutettua tiedostoa jossa 1120 lisäystä ja 0 poistoa
  1. +8
    -0
      .babelrc
  2. +35
    -0
      .gitignore
  3. +5
    -0
      .thinkjsrc
  4. +22
    -0
      README.md
  5. +120
    -0
      nginx.conf
  6. +30
    -0
      package.json
  7. +18
    -0
      pm2.json
  8. +12
    -0
      src/common/bootstrap/global.js
  9. +13
    -0
      src/common/bootstrap/middleware.js
  10. +7
    -0
      src/common/config/config.js
  11. +22
    -0
      src/common/config/db.js
  12. +15
    -0
      src/common/config/env/development.js
  13. +15
    -0
      src/common/config/env/live.js
  14. +5
    -0
      src/common/config/env/production.js
  15. +5
    -0
      src/common/config/env/testing.js
  16. +9
    -0
      src/common/config/error.js
  17. +9
    -0
      src/common/config/hook.js
  18. +5
    -0
      src/common/config/locale/en.js
  19. +20
    -0
      src/common/config/session.js
  20. +14
    -0
      src/common/config/view.js
  21. +77
    -0
      src/common/controller/error.js
  22. +7
    -0
      src/home/config/config.js
  23. +7
    -0
      src/home/controller/base.js
  24. +236
    -0
      src/home/controller/index.js
  25. +15
    -0
      src/home/logic/index.js
  26. +7
    -0
      src/home/model/index.js
  27. +0
    -0
      ssl/cert/.keep
  28. +0
    -0
      ssl/lechallenge/.keep
  29. +0
    -0
      ssl/letsencrypt/.keep
  30. +37
    -0
      view/common/error_400.html
  31. +37
    -0
      view/common/error_403.html
  32. +37
    -0
      view/common/error_404.html
  33. +37
    -0
      view/common/error_500.html
  34. +37
    -0
      view/common/error_503.html
  35. +72
    -0
      view/home/index_index.html
  36. +55
    -0
      www/README.md
  37. +21
    -0
      www/development.js
  38. +21
    -0
      www/live.js
  39. +14
    -0
      www/production.js
  40. +14
    -0
      www/testing.js

+ 8
- 0
.babelrc Näytä tiedosto

@@ -0,0 +1,8 @@
{
"presets": [
["es2015", {"loose": true}],
"stage-1"
],
"plugins": ["transform-runtime"],
"sourceMaps": true
}

+ 35
- 0
.gitignore Näytä tiedosto

@@ -0,0 +1,35 @@
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage/

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules/

# IDE config
.idea

# output
output/
output.tar.gz

app/

runtime/

+ 5
- 0
.thinkjsrc Näytä tiedosto

@@ -0,0 +1,5 @@
{
"createAt": "2025-03-25 17:17:46",
"mode": "module",
"es": true
}

+ 22
- 0
README.md Näytä tiedosto

@@ -0,0 +1,22 @@

Application created by [ThinkJS](http://www.thinkjs.org)

## Install dependencies

```
npm install
```

## Start server

```
npm start
```

## Deploy with pm2

Use pm2 to deploy app on production enviroment.

```
pm2 startOrReload pm2.json
```

+ 120
- 0
nginx.conf Näytä tiedosto

@@ -0,0 +1,120 @@
server {
listen 80;
server_name example.com www.example.com;
root D:\demo\ssl\ssl_manage/www;
set $node_port 8360;

index index.js index.html index.htm;
if ( -f $request_filename/index.html ){
rewrite (.*) $1/index.html break;
}
if ( !-f $request_filename ){
rewrite (.*) /index.js;
}
location = /index.js {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://127.0.0.1:$node_port$request_uri;
proxy_redirect off;
}
location = /development.js {
deny all;
}

location = /testing.js {
deny all;
}

location = /production.js {
deny all;
}

location ~ /static/ {
etag on;
expires max;
}
}




## http/2 nginx conf

# server {
# listen 80;
# server_name example.com www.example.com;
# rewrite ^(.*) https://example.com$1 permanent;
# }
#
# server {
# listen 443 ssl http2 fastopen=3 reuseport;
# server_name www.thinkjs.org thinkjs.org;
# set $node_port 8360;
#
# root D:\demo\ssl\ssl_manage/www;
#
# keepalive_timeout 70;
#
# ssl_certificate /path/to/certificate;
# ssl_certificate_key /path/to/certificate.key;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
# ssl_prefer_server_ciphers on;

# # openssl dhparam -out dhparams.pem 2048
# ssl_dhparam /path/to/dhparams.pem;
#
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 10m;
#
# ssl_session_ticket_key /path/to/tls_session_ticket.key;
# ssl_session_tickets on;
#
# ssl_stapling on;
# ssl_stapling_verify on;
# ssl_trusted_certificate /path/to/startssl_trust_chain.crt;
#
#
# add_header x-Content-Type-Options nosniff;
# add_header X-Frame-Options deny;
# add_header Strict-Transport-Security "max-age=16070400";
#
# index index.js index.html index.htm;
# if ( -f $request_filename/index.html ){
# rewrite (.*) $1/index.html break;
# }
# if ( !-f $request_filename ){
# rewrite (.*) /index.js;
# }
# location = /index.js {
# proxy_http_version 1.1;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header Host $http_host;
# proxy_set_header X-NginX-Proxy true;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# proxy_pass http://127.0.0.1:$node_port$request_uri;
# proxy_redirect off;
# }
#
# location = /production.js {
# deny all;
# }
#
# location = /testing.js {
# deny all;
# }
#
# location ~ /static/ {
# etag on;
# expires max;
# }
#}


+ 30
- 0
package.json Näytä tiedosto

@@ -0,0 +1,30 @@
{
"name": "thinkjs-application",
"description": "application created by thinkjs",
"version": "1.0.0",
"scripts": {
"start": "node www/development.js",
"compile": "babel src/ --out-dir app/",
"watch-compile": "node -e \"console.log('<npm run watch-compile> no longer need, use <npm start> command direct.');console.log();\"",
"watch": "npm run watch-compile"
},
"dependencies": {
"babel-runtime": "6.x.x",
"dayjs": "^1.11.13",
"fs-extra": "^11.3.0",
"greenlock": "^2.8.9",
"greenlock-store-fs": "^3.2.2",
"le-challenge-fs": "^2.0.9",
"source-map-support": "0.4.0",
"thinkjs": "v2"
},
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-1": "^6.16.0",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-core": "^6.20.0"
},
"repository": "",
"license": "MIT"
}

+ 18
- 0
pm2.json Näytä tiedosto

@@ -0,0 +1,18 @@
{
"apps": [
{
"name": "ssl",
"script": "www/live.js",
"cwd": "/home/program/front/git/ssl_manage",
"exec_mode": "cluster",
"instances": 1,
"max_memory_restart": "2G",
"autorestart": true,
"node_args": [],
"args": [],
"env": {},
"error_file": "/data/pm2/logs/ssl-err.log",
"out_file": "/data/pm2/logs/ssl-out.log"
}
]
}

+ 12
- 0
src/common/bootstrap/global.js Näytä tiedosto

@@ -0,0 +1,12 @@
/**
* this file will be loaded before server started
* you can define global functions used in controllers, models, templates
*/

/**
* use global.xxx to define global functions
*
* global.fn1 = function(){
*
* }
*/

+ 13
- 0
src/common/bootstrap/middleware.js Näytä tiedosto

@@ -0,0 +1,13 @@
/**
* this file will be loaded before server started
* you can register middleware
* https://thinkjs.org/doc/middleware.html
*/

/**
*
* think.middleware('xxx', http => {
*
* })
*
*/

+ 7
- 0
src/common/config/config.js Näytä tiedosto

@@ -0,0 +1,7 @@
'use strict';
/**
* config
*/
export default {
//key: value
};

+ 22
- 0
src/common/config/db.js Näytä tiedosto

@@ -0,0 +1,22 @@
'use strict';
/**
* db config
* @type {Object}
*/
export default {
type: 'mysql',
adapter: {
mysql: {
host: '127.0.0.1',
port: '',
database: '',
user: '',
password: '',
prefix: '',
encoding: 'utf8'
},
mongo: {

}
}
};

+ 15
- 0
src/common/config/env/development.js Näytä tiedosto

@@ -0,0 +1,15 @@
'use strict';

export default {
domains:[
// "oa.live.educlouddata.com",
// "m.live.educlouddata.com",
// "yun.live.educlouddata.com",
// "yunh5.live.educlouddata.com",
// "kms.live.educlouddata.com",
// "ams.live.educlouddata.com",
// "data.live.educlouddata.com",
"live.qqsrx.top",
],
CERT_DIR:"/usr/local/nginx/conf/cert"
};

+ 15
- 0
src/common/config/env/live.js Näytä tiedosto

@@ -0,0 +1,15 @@
'use strict';

export default {
domains:[
// "oa.live.educlouddata.com",
// "m.live.educlouddata.com",
// "yun.live.educlouddata.com",
// "yunh5.live.educlouddata.com",
// "kms.live.educlouddata.com",
// "ams.live.educlouddata.com",
// "data.live.educlouddata.com",
"live.qqsrx.top",
],
CERT_DIR:"/usr/local/nginx/conf/cert"
};

+ 5
- 0
src/common/config/env/production.js Näytä tiedosto

@@ -0,0 +1,5 @@
'use strict';

export default {
resource_on: false
};

+ 5
- 0
src/common/config/env/testing.js Näytä tiedosto

@@ -0,0 +1,5 @@
'use strict';

export default {
};

+ 9
- 0
src/common/config/error.js Näytä tiedosto

@@ -0,0 +1,9 @@
'use strict';
/**
* err config
*/
export default {
//key: value
key: 'errno', //error number
msg: 'errmsg' //error message
};

+ 9
- 0
src/common/config/hook.js Näytä tiedosto

@@ -0,0 +1,9 @@
'use strict';

/**
* hook config
* https://thinkjs.org/doc/middleware.html#toc-df6
*/
export default {

}

+ 5
- 0
src/common/config/locale/en.js Näytä tiedosto

@@ -0,0 +1,5 @@
'use strict';

export default {
};

+ 20
- 0
src/common/config/session.js Näytä tiedosto

@@ -0,0 +1,20 @@
'use strict';

/**
* session configs
*/
export default {
name: 'thinkjs',
type: 'file',
secret: 'VH7!OBT^',
timeout: 24 * 3600,
cookie: { // cookie options
length: 32,
httponly: true
},
adapter: {
file: {
path: think.RUNTIME_PATH + '/session',
}
}
};

+ 14
- 0
src/common/config/view.js Näytä tiedosto

@@ -0,0 +1,14 @@
'use strict';
/**
* template config
*/
export default {
type: 'ejs',
content_type: 'text/html',
file_ext: '.html',
file_depr: '_',
root_path: think.ROOT_PATH + '/view',
adapter: {
ejs: {}
}
};

+ 77
- 0
src/common/controller/error.js Näytä tiedosto

@@ -0,0 +1,77 @@
'use strict';
/**
* error controller
*/
export default class extends think.controller.base {
/**
* display error page
* @param {Number} status []
* @return {Promise} []
*/
displayError(status){

//hide error message on production env
if(think.env === 'production'){
this.http.error = null;
}

let errorConfig = this.config('error');
let message = this.http.error && this.http.error.message || '';
if(this.isJsonp()){
return this.jsonp({
[errorConfig.key]: status,
[errorConfig.msg]: message
})
}else if(this.isAjax()){
return this.fail(status, message);
}

let module = 'common';
if(think.mode !== think.mode_module){
module = this.config('default_module');
}
let file = `${module}/error/${status}.html`;
let options = this.config('tpl');
options = think.extend({}, options, {type: 'base', file_depr: '_'});
this.fetch(file, {}, options).then(content => {
content = content.replace('ERROR_MESSAGE', message);
this.type(options.content_type);
this.end(content);
});
}
/**
* Bad Request
* @return {Promise} []
*/
_400Action(){
return this.displayError(400);
}
/**
* Forbidden
* @return {Promise} []
*/
_403Action(){
return this.displayError(403);
}
/**
* Not Found
* @return {Promise} []
*/
_404Action(){
return this.displayError(404);
}
/**
* Internal Server Error
* @return {Promise} []
*/
_500Action(){
return this.displayError(500);
}
/**
* Service Unavailable
* @return {Promise} []
*/
_503Action(){
return this.displayError(503);
}
}

+ 7
- 0
src/home/config/config.js Näytä tiedosto

@@ -0,0 +1,7 @@
'use strict';
/**
* config
*/
export default {
//key: value
};

+ 7
- 0
src/home/controller/base.js Näytä tiedosto

@@ -0,0 +1,7 @@
'use strict';

export default class extends think.controller.base {
/**
* some base method in here
*/
}

+ 236
- 0
src/home/controller/index.js Näytä tiedosto

@@ -0,0 +1,236 @@
'use strict';

import Base from './base.js';

const Greenlock = require('greenlock');
const path = require('path');
const GreenlockStoreFs = require('greenlock-store-fs');
const LeChallengeFs = require('le-challenge-fs');
const fs = require('fs-extra');
const { execSync } = require('child_process');
const https = require('https');
const dayjs = require('dayjs'); // 需安装dayjs库


// SSL根目录
const ROOT_PATH = path.join(think.ROOT_PATH, 'ssl');
const PEM_PATH = path.join(ROOT_PATH, 'cert');
// 创建存储对象
const leStore = GreenlockStoreFs.create({
configDir: path.join(ROOT_PATH, 'letsencrypt'),
});
// 创建验证对象
const leHttpChallenge = LeChallengeFs.create({
webrootPath: path.join(ROOT_PATH, 'lechallenge'),
});
// 是否同意协议
function leAgree (opts, agreeCb) {
agreeCb(null, opts.tosUrl);
}

// 证书申请对象
const greenlock = Greenlock.create({
version: 'draft-12',
// 测试环境
server: 'https://acme-staging-v02.api.letsencrypt.org/directory',
// 生产环境
// server: 'https://acme-v02.api.letsencrypt.org/directory',
store: leStore,
challenges: {
'http-01': leHttpChallenge,
},
challengeType: 'http-01',
agreeToTerms: leAgree,
debug: true,
renewBy: 10 * 24 * 60 * 60 * 1000,// 10倒计时开始续期
});


// 创建SSL证书申请请求
async function CreateSSL (domain, email = '') {
const results = await greenlock.register({
domains: [domain],
email,
agreeTos: true,
rsaKeySize: 2048,
});
// 如果生成证书就保存一次证书
const dir = path.join(PEM_PATH, domain);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
if (results.cert && results.chain) {
fs.writeFileSync(path.join(dir, `${domain}.crt`), results.cert + results.chain, 'utf-8');
console.log(`证书${domain}.crt创建成功!`);
}
if (results.privkey) {
fs.writeFileSync(path.join(dir, `${domain}.key`), results.privkey, 'utf-8');
console.log(`证书${domain}.key创建成功!`);
}
return results;
}


/**
* 检查证书过期时间
* @param {*} domain
* @returns
*/
function checkCertExpiry (domain) {
return new Promise((resolve, reject) => {
const req = https.request({
hostname: domain,
port: 443,
method: 'GET',
agent: new https.Agent({ rejectUnauthorized: false }) // 避免自签名证书报错
}, (res) => {
const cert = res.socket.getPeerCertificate();
if (cert.valid_to) {
resolve(cert.valid_to);
} else {
reject(new Error('证书信息缺失'));
}
});

req.on('error', (err) => reject(err));
req.end();
});
}

/**
*
* @param {*} domain
* @returns
*/
async function getRemainingDays (domain) {
try {
const validTo = await checkCertExpiry(domain);
const expiryDate = dayjs(validTo, 'MMM DD HH:mm:ss YYYY GMT'); // 解析时间格式
const currentDate = dayjs();
const daysLeft = expiryDate.diff(currentDate, 'day');
return daysLeft;
} catch (err) {
console.error(`检测失败:${err.message}`);
return -1; // 错误时返回-1
}
}




export default class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction () {
let domains = this.config().domains;
let msgs = []
for (let domain of domains) {
try {
const daysLeft = await getRemainingDays(domain);
const msg = `证书${domain},剩余${daysLeft}天`
console.log(msg);
msgs.push(msg);
} catch (e) {
const msg = `证书${domain},证书缺失或无法访问`
console.log(e);
msgs.push(msg);
}
}
this.assign({
msgs: msgs.join('\n')
});
return this.display();
}

/**
* 检查并更新证书
*/
async checksslAction () {
let domains = this.config().domains;
let updateList = []; //需要更新的数据
for (let domain of domains) {
try {
const daysLeft = await getRemainingDays(domain);
const msg = `证书${domain},剩余${daysLeft}天`;
console.log(msg);
if (daysLeft < 90) {
updateList.push(domain);
}
} catch (e) {
console.log("==".repeat(20))
console.log('检查证书失败:', e);
console.log("==".repeat(20))
}
}
if (updateList.length) {
console.log("==".repeat(20), "开始生成证书", "==".repeat(20));
console.log('开始时间:', dayjs().format('YYYY-MM-DD HH:mm:ss'));
for (let domain of updateList) {
try {
const results = await CreateSSL(domain);
console.log(`证书${domain},生成成功`);
} catch (error) {
console.log("==".repeat(20), "证书生成失败", "==".repeat(20));
console.log("域名:", domain);
console.log(e);
console.log("==".repeat(20), "证书生成失败", "==".repeat(20));
}
}
await this.deployCert(updateList);
console.log(`更新证书数量:${updateList.length}`);
console.log('结束时间:', dayjs().format('YYYY-MM-DD HH:mm:ss'));
console.log("==".repeat(20), "结束生成证书", "==".repeat(20));
}
this.success();
}

async createAction () {
const domain = this.post('domain');
const email = this.post('email');
if (!domain || !email) {
return this.fail('参数错误');
}
try {
const results = await CreateSSL(domain, email);
this.deployCert([domain]);
return this.success(results);
} catch (error) {
return this.fail(JSON.stringify(error));
}
}

/**
* 复制证书到指定文件夹,并重启nginx
* @param {*} domains
* @returns
*/
async deployCert (domains) {
if (!domains || domains.length === 0) {
return;
}
try {
const dir2 = this.config().CERT_DIR; //nginx配置文件中
// 1. 复制证书
for (let domain of domains) {
const dir = path.join(PEM_PATH, domain); //生成的证书地址,项目中
let originCrt = `${dir}/${domain}.crt`;
let originKey = `${dir}/${domain}.key`;
if (fs.existsSync(originCrt) && fs.existsSync(originKey)) {
await fs.copy(`${dir}/${domain}.crt`, `${dir2}/${domain}.crt`);
await fs.copy(`${dir}/${domain}.key`, `${dir2}/${domain}.key`);
}
}

// 2. 检查配置
execSync('nginx -t');

// 3. 重载服务
execSync('nginx -s reload');
console.log('证书部署成功!');
} catch (error) {
console.error('部署失败:', error.message);
}
}
}

+ 15
- 0
src/home/logic/index.js Näytä tiedosto

@@ -0,0 +1,15 @@
'use strict';
/**
* logic
* @param {} []
* @return {} []
*/
export default class extends think.logic.base {
/**
* index action logic
* @return {} []
*/
indexAction(){
}
}

+ 7
- 0
src/home/model/index.js Näytä tiedosto

@@ -0,0 +1,7 @@
'use strict';
/**
* model
*/
export default class extends think.model.base {

}

+ 0
- 0
ssl/cert/.keep Näytä tiedosto


+ 0
- 0
ssl/lechallenge/.keep Näytä tiedosto


+ 0
- 0
ssl/letsencrypt/.keep Näytä tiedosto


+ 37
- 0
view/common/error_400.html
File diff suppressed because it is too large
Näytä tiedosto


+ 37
- 0
view/common/error_403.html
File diff suppressed because it is too large
Näytä tiedosto


+ 37
- 0
view/common/error_404.html
File diff suppressed because it is too large
Näytä tiedosto


+ 37
- 0
view/common/error_500.html
File diff suppressed because it is too large
Näytä tiedosto


+ 37
- 0
view/common/error_503.html
File diff suppressed because it is too large
Näytä tiedosto


+ 72
- 0
view/home/index_index.html Näytä tiedosto

@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>New ThinkJS Application</title>
<style>
* {
padding: 0;
margin: 0;
font-size: 16px;
line-height: 20px;
font-family: arial;
}

a,
a:visited {
color: #337ab7;
text-decoration: none;
}

header {
padding: 70px 0 70px 0;
background-color: #4A6495
}

h1 {
font-size: 36px;
color: #fff;
font-weight: normal;
}

code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
border-radius: 4px;
}

.content {
width: 1000px;
margin: auto
}

.wrap {
width: 1000px;
margin: auto
}

.list {
width: 800px;
white-space: pre-line;
line-height: 3;
}
</style>
</head>

<body>
<header>
<div class="wrap">
<h1>证书自动更新系统</h1>
</div>
</header>
<div class="content">
<div class="list">
<%= msgs %>
</div>
</div>
</body>

</html>

+ 55
- 0
www/README.md Näytä tiedosto

@@ -0,0 +1,55 @@
## application

### start server

*development*

```js
node www/development.js
```

*testing*

```js
node www/testing.js
```

*production*

```js
node www/production.js
```

or use pm2 to manage node:

```
pm2 start www/production.js
```

### compile es6 code

```
npm run compile
```

### how to link resource

*in template file*

```html

<script src="/static/js/a.js"></script>

<img src="/static/img/a.png" alt="">

<link rel="stylesheet" href="/static/css/a.js">

```

*link image in css*

```css
.a{
background: url(../img/a.png) no-repeat;
}
```

+ 21
- 0
www/development.js Näytä tiedosto

@@ -0,0 +1,21 @@
var thinkjs = require('thinkjs');
var path = require('path');

var rootPath = path.dirname(__dirname);

var instance = new thinkjs({
APP_PATH: rootPath + path.sep + 'app',
RUNTIME_PATH: rootPath + path.sep + 'runtime',
ROOT_PATH: rootPath,
RESOURCE_PATH: __dirname,
env: 'development'
});

// Build code from src to app directory.
instance.compile({
log: true,
presets: [],
plugins: []
});

instance.run();

+ 21
- 0
www/live.js Näytä tiedosto

@@ -0,0 +1,21 @@
var thinkjs = require('thinkjs');
var path = require('path');

var rootPath = path.dirname(__dirname);

var instance = new thinkjs({
APP_PATH: rootPath + path.sep + 'app',
RUNTIME_PATH: rootPath + path.sep + 'runtime',
ROOT_PATH: rootPath,
RESOURCE_PATH: __dirname,
env: 'live'
});

// Build code from src to app directory.
instance.compile({
log: true,
presets: [],
plugins: []
});

instance.run();

+ 14
- 0
www/production.js Näytä tiedosto

@@ -0,0 +1,14 @@
var thinkjs = require('thinkjs');
var path = require('path');

var rootPath = path.dirname(__dirname);

var instance = new thinkjs({
APP_PATH: rootPath + path.sep + 'app',
RUNTIME_PATH: rootPath + path.sep + 'runtime',
ROOT_PATH: rootPath,
RESOURCE_PATH: __dirname,
env: 'production'
});

instance.run(true);

+ 14
- 0
www/testing.js Näytä tiedosto

@@ -0,0 +1,14 @@
var thinkjs = require('thinkjs');
var path = require('path');

var rootPath = path.dirname(__dirname);

var instance = new thinkjs({
APP_PATH: rootPath + path.sep + 'app',
RUNTIME_PATH: rootPath + path.sep + 'runtime',
ROOT_PATH: rootPath,
RESOURCE_PATH: __dirname,
env: 'testing'
});

instance.run();

Ladataan…
Peruuta
Tallenna