## 前言
基于前面的了解或者公司內部的剛需,可能搭建cnpm倉庫已經變成了你必須會的知識點。跟著我一起去服務器部署一個私有的cnpm倉庫吧。
### 環境要求
* 系統要求:mac或者linux(服務器基本都是linux的)
* nodejs:4.2.3 以上版本
### 基本安裝
* nodejs
~~~
curl -sL https://rpm.nodesource.com/setup_7.x | bash - (腳本)
yum install -y nodejs
yum install -y gcc-c++ make
~~~
* 安裝mysql
1. 檢測并卸載已有的
~~~
rpm -qa | grep mariadb
rpm -e --nodeps mariadb/mysql
~~~
2. 安裝mysql-server
2.1 在/etc/yum.repos.d/目錄創建MariaDB.repo文件,內容如下:
~~~
# MariaDB 5.5 CentOS repository list - created 2014-03-04 11:20 UTC
# http://mariadb.org/mariadb/repositories/
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/5.5/centos6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
~~~
2.2 安裝對應包
~~~
sudo yum -y install mariadb-server MariaDB-client
~~~
2.3 啟動服務
~~~
//如果你是centos 系統
systemctl start mariadb.service
//如果你是GUN/linux ,只有service服務
service mysql start
//修改數據庫密碼,默認是空的
mysqladmin -u root password "passwd"
~~~
2.4 相關命令的拓展
~~~
//centos 系統
systemctl start mariadb #啟動服務
systemctl enable mariadb #設置開機啟動
systemctl restart mariadb #重新啟動
systemctl stop mariadb.service #停止MariaDB
// gun
service xxxx start/stop/enable/restart
~~~
* 安裝git并檢出cnpmjs項目
~~~
//安裝git 下載cnpmjs的git項目
yum install git
git clone git://github.com/fengmk2/cnpmjs.org.git $HOME/cnpmjs.org
cd cnpmjs.org
//用戶登陸 修改相關的庫表信息
Mysql -u root -p
create database cnpmjs;
use cnpmjs;
source docs/db.sql【db.sql位于cnpmjs.org/docs/db.sql】
//允許外部鏈接數據庫(如果 你想查看數據庫的情況有必要設置)
grant all privileges on *.* to root@'%' identified by 'password';
//根據自己的需要修改index的配置文件
vim config/index.js
~~~
### 使用須知
* cnpm提供兩個端口:7001和7002,其中7001用于NPM的注冊服務,7002用于Web訪問。
* bindingHost為安裝cnpm的服務器ip地址,也就是在瀏覽器中只能通過訪問http://192.168.0.234來訪問cnpm以及獲取npm的注冊服務。
修改本地下載地址(registryHost:r.cnpmjs.org修改為192.168.0.129:7001)
* 安裝依賴
~~~
//持久使用
npm config set registry https://registry.npm.taobao.org
// 配置后可通過下面方式來驗證是否成功
npm config get registry// 或
npm info express
//進入./cnpmjs.org,執行npm install
npm install
~~~
* 啟動服務
node dispatch.js或者“nohup node dispatch.js &”來啟動。
其中nohup為在后臺啟動。
~~~
npm run dev:調試模式啟動;
npm run test:跑測試;
npm run start:啟動 CNPM;永久的熱啟動
npm run status:查看 CNPM 啟動狀態;
npm run stop:停止 CNPM。
~~~
* 如果啟動時報錯:`/lib64/libc.so.6: version `GLIBC_2.14' not found`,這個是因為glibc版本過低引起的,你可以通過命令查看目前支持的版本:`strings /lib64/libc.so.6 |grep GLIBC ` ,解決辦法從官網下載相關的壓縮包然后編譯安裝,再配置到相關的目錄下。
1. 找到官網:http://www.gnu.org/software/libc/,下載2.14版本后綴為gz的壓縮包,我們下載后放到root/software 下
2. 剩下的都是命令行操作
~~~cmd
//解壓
[root@jrgc130 ~]#tar zxf glibc-2.14.tar.gz
[root@jrgc130 ~]# cd /opt/software
[root@jrgc130 software]# tar xf glibc-2.14.tar.gz
[root@jrgc130 software]# cd glibc-2.14
[root@jrgc130 glibc-2.14]# mkdir build
[root@jrgc130 glibc-2.14]# cd build
//修改配置文件
[root@jrgc130 build]# ../configure --prefix=/usr/local/glibc-2.14
//安裝
[root@jrgc130 build]# make -j4
[root@jrgc130 build]# make install
//拷貝鏈接庫
[root@jrgc130 build]# cd /usr/local/glibc-2.14/lib
[root@jrgc130 lib]# cp libc-2.16.so /lib64/
//創建鏈接
[root@jrgc130 lib]# cd /lib64
[root@jrgc130 lib64]# rm -rf libc.so.6
//復制相關文件到so
[root@example lib64]# /sbin/sln libc-2.14.so /lib64/libc.so.6
//運行strings /lib64/libc.so.6 |grep GLIBC 可以查看最新支持版本為2.14,問題解決。
~~~
* 測試是否啟動成功
~~~
在瀏覽器中輸入:http://192.168.0.234:7002/,如果出現:
發布私有包
npm config set registry https://registry.npm.taobao.org
安裝cnpm客戶端
curl -sL https://rpm.nodesource.com/setup_7.x | bash - (腳本)
yum install -y nodejs
sudo npm install cnpm -g
更改默認的registry,指向私有的registry
cnpm set registry http://192.168.0.234:7001
~~~
* 用npm賬號登錄你的私有registry
這里的賬號中www.npmjs.com的賬號,沒有請注冊(admin登錄)
~~~
$ cnpm login
Username: admin
Password: npm0816@zjkj.com
Email: (this IS public) admin@cnpmjs.org
~~~
* 如果過程中遇到不能同步或者下載自己的模塊 ,可以修改/config/index.js 文件
> enableAbbreviatedMetadata: true
### 創建私有測試包
* 生成測試包
~~~
$ cd /tmp
$ mkdir helloworld && cd helloworld
$ cnpm init
name: @cjt/helloworld
version: 1.0.0
~~~
* 生成package.json(產出文件) :
~~~
{
"name": "@cjt/helloworld",
"version": "1.0.0",
"description": "my first scoped package",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
~~~
* 注意事項
1. 注意,包名helloworld前必須要以公司名@cjt為前綴, @cjt在 config/index.js的scopes中配置
~~~
// registry scopes, if don't set, means do not support scopes,你可以設置為kkl
scopes: [ '@cjt','@cnpm', '@cnpmtest', '@cnpm-test' ],
~~~
2. 其余管理員賬號權限分配必須二次開發,修改 `middleware/publishable.js` ,也可以直接修改index.js中的文件,默認的管理員是admin ;
3. 注冊并登陸用戶:

3. 發布與同步(見cnpm入門)
~~~
發布
cnpm publish
通過瀏覽器訪問:http://192.168.0.129:7002/?可查看和操作私有CNPM服務器
從默認源同步gulp
cnpm sync gulp
下載
cnpm install gulp
~~~
## 配置文件(config/index.js)
~~~
'use strict';
var mkdirp = require('mkdirp');
var copy = require('copy-to');
var path = require('path');
var fs = require('fs');
var os = require('os');
var version = require('../package.json').version;
var root = path.dirname(__dirname);
var dataDir = path.join(process.env.HOME || root, '.cnpmjs.org');
var config = {
version: version,
dataDir: dataDir,
/**
* Cluster mode 是否啟用?cluster-worker?模式啟動服務,默認?false,生產環節推薦為?true; 利用多核
*/
enableCluster: true,
numCPUs: os.cpus().length,
/*
* server configure 服務器的基本設置,ip以及請求以及訪問端口(必須設置)
*/
registryPort: 7001,
webPort: 7002,
bindingHost: '10.0.0.141', // only binding on 127.0.0.1 for local access
// debug mode
// if in debug mode, some middleware like limit wont load
// logger module will print to stdout
debug: process.env.NODE_ENV === 'development',
// page mode, enable on development env
pagemock: process.env.NODE_ENV === 'development',
// session secret
sessionSecret: 'cnpmjs.org test session secret',
// max request json body size
jsonLimit: '10mb',
// log dir name
logdir: path.join(dataDir, 'logs'),
// update file template dir
uploadDir: path.join(dataDir, 'downloads'),
// web page viewCache
viewCache: false,
// config for koa-limit middleware
// for limit download rates
limit: {
enable: false,
token: 'koa-limit:download',
limit: 1000,
interval: 1000 * 60 * 60 * 24,
whiteList: [],
blackList: [],
message: 'request frequency limited, any question, please contact fengmk2@gmail.com',
},
enableCompress: false, // enable gzip response or not
// default system admins,(管理員必須設置為自己清楚的,只有管理員可以刪除模塊,配置需要重啟)
admins: {
// name: email
fengmk2: 'fengmk2@gmail.com',
admin: 'admin@cnpmjs.org',
dead_horse: 'dead_horse@qq.com',
},
// email notification for errors
// check https://github.com/andris9/Nodemailer for more informations
mail: {
enable: false,
appname: 'cnpmjs.org',
from: 'cnpmjs.org mail sender <adderss@gmail.com>',
service: 'gmail',
auth: {
user: 'address@gmail.com',
pass: 'your password'
}
},
logoURL: 'https://os.alipayobjects.com/rmsportal/oygxuIUkkrRccUz.jpg', // cnpm logo image url
adBanner: '',
customReadmeFile: '', // you can use your custom readme file instead the cnpm one
customFooter: '', // you can add copyright and site total script html here
npmClientName: 'cnpm', // use `${name} install package`,(默認的安裝命令符號)
packagePageContributorSearch: true, // package page contributor link to search, default is true
// max handle number of package.json `dependencies` property
maxDependencies: 200,
// backup filepath prefix
backupFilePrefix: '/cnpm/backup/',
/**
* database config(數據庫配置文件,必須設置的)
*/
database: {
db: 'cnpmjs',
username: 'root',
password: 'kkl123456',
// the sql dialect of the database
// - currently supported: 'mysql', 'sqlite', 'postgres', 'mariadb'
dialect: 'mariadb',
// custom host; default: 127.0.0.1
host: '127.0.0.1',
// custom port; default: 3306
port: 3306,
// use pooling in order to reduce db connection overload and to increase speed
// currently only for mysql and postgresql (since v1.5.0)
pool: {
maxConnections: 10,
minConnections: 0,
maxIdleTime: 30000
},
// the storage engine for 'sqlite'
// default store into ~/.cnpmjs.org/data.sqlite
storage: path.join(dataDir, 'data.sqlite'),
logging: !!process.env.SQL_DEBUG,
},
// package tarball store in local filesystem by default(文件系統,可以默認,可以用其他云服務器)
nfs: require('fs-cnpm')({
dir: path.join(dataDir, 'nfs')
}),
// if set true, will 302 redirect to `nfs.url(dist.key)`
downloadRedirectToNFS: false,
// registry url name(模塊下載請求地址,必須設置)
registryHost: '10.0.0.141:7001',
/**
* registry mode config
*/
// enable private mode or not(必須設置,false允許其他人發布,否則只有管理員)
// private mode: only admins can publish, other users just can sync package from source npm
// public mode: all users can publish
enablePrivate: false,
// registry scopes, if don't set, means do not support scopes(私有模塊前綴,必須設置)
scopes: [ '@kkl'],
// some registry already have some private packages in global scope
// but we want to treat them as scoped private packages,
// so you can use this white list.
privatePackages: [],
/**
* sync configs
*/
// the official npm registry(官方請求地址,一般不用修改)
// cnpm wont directly sync from this one
// but sometimes will request it for some package infomations
// please don't change it if not necessary
officialNpmRegistry: 'http://registry.npm.taobao.org',
officialNpmReplicate: 'https://replicate.npmjs.com',
// sync source, upstream registry(同步模塊的地址,設置為阿里鏡像建議)
// If you want to directly sync from official npm's registry
// please drop them an email first
sourceNpmRegistry: 'http://registry.npm.taobao.org',
// upstream registry is base on cnpm/cnpmjs.org or not
// if your upstream is official npm registry, please turn it off
sourceNpmRegistryIsCNpm: true,
// if install return 404, try to sync from source registry(模塊沒有,從遠程更新下載,必須設置)
syncByInstall: true,
// sync mode select(同步模式,同步已有模塊即可)
// none: do not sync any module, proxy all public modules from sourceNpmRegistry
// exist: only sync exist modules
// all: sync all modules
syncModel: 'exist', // 'none', 'all', 'exist'
syncConcurrency: 1,
// sync interval, default is 10 minutes(10ms同步一次)
syncInterval: '10m',
// sync polular modules, default to false(不同步熱門模塊)
// because cnpm can't auto sync tag change for now
// so we want to sync popular modules to ensure their tags
syncPopular: false,
syncPopularInterval: '1h',
// top 100
topPopular: 100,
// sync devDependencies or not, default is false
syncDevDependencies: false,
// changes streaming sync
syncChangesStream: false,
handleSyncRegistry: 'http://127.0.0.1:7001',
// badge subject on http://shields.io/
badgePrefixURL: 'https://img.shields.io/badge',
badgeSubject: 'cnpm',
// custom user service, @see https://github.com/cnpm/cnpmjs.org/wiki/Use-Your-Own-User-Authorization
// when you not intend to ingegrate with your company's user system, then use null, it would
// use the default cnpm user system
userService: null,
// always-auth https://docs.npmjs.com/misc/config#always-auth
// Force npm to always require authentication when accessing the registry, even for GET requests.
alwaysAuth: false,
// if you're behind firewall, need to request through http proxy, please set this
// e.g.: `httpProxy: 'http://proxy.mycompany.com:8080'`
httpProxy: null,
// snyk.io root url
snykUrl: 'https://snyk.io',
// https://github.com/cnpm/cnpmjs.org/issues/1149(針對某個補丁文件的修復,必須設置)
// if enable this option, must create module_abbreviated and package_readme table in database
enableAbbreviatedMetadata: true,
// global hook function: function* (envelope) {}
// envelope format please see https://github.com/npm/registry/blob/master/docs/hooks/hooks-payload.md#payload
globalHook: null,
};
if (process.env.NODE_ENV === 'test') {
config.enableAbbreviatedMetadata = true;
}
if (process.env.NODE_ENV !== 'test') {
var customConfig;
if (process.env.NODE_ENV === 'development') {
customConfig = path.join(root, 'config', 'config.js');
} else {
// 1. try to load `$dataDir/config.json` first, not exists then goto 2.
// 2. load config/config.js, everything in config.js will cover the same key in index.js
customConfig = path.join(dataDir, 'config.json');
if (!fs.existsSync(customConfig)) {
customConfig = path.join(root, 'config', 'config.js');
}
}
if (fs.existsSync(customConfig)) {
copy(require(customConfig)).override(config);
}
}
mkdirp.sync(config.logdir);
mkdirp.sync(config.uploadDir);
module.exports = config;
config.loadConfig = function (customConfig) {
if (!customConfig) {
return;
}
copy(customConfig).override(config);
};
~~~
### 參考測試文檔
* [cnpm配置](http://blog.csdn.net/xs20691718/article/details/51898164)
* [cnpm官網文檔介紹](https://github.com/cnpm/cnpmjs.org/wiki)
- 前端工程化
- 架構總綱
- 001
- 美團技術架構
- 前端工程化說明
- 歷史背景說明
- 架構說明
- 前端工程化技術棧
- 技術文檔說明
- 功能模塊說明
- 前端模塊管理器簡介
- 框架對比分析
- vue&react&ng對比分析(一)
- vue&react&ng對比分析(二)
- vue&react&ng對比分析(三)
- 工程化專題系列
- 需要解決的問題
- 001
- 002
- 003
- 常見代碼錯誤
- jslint中常見的錯誤
- css規范常見錯誤
- html規范常見錯誤
- 工程化目錄
- 工程化初始化
- 項目構建流程
- 項目打包優化
- 上線與迭代注意事項
- 前端部署發布
- jetkins部署
- 部署需求整理
- 前端監控
- 工程化實踐指南
- dock持續部署
- 系列文章
- 插拔式前端的設計
- 其他實踐
- 工程化的前端管理
- 宋小菜借鑒
- 大前端團隊介紹
- 人員組成
- 人員發展
- 研發流程
- 任務分類
- 前端基礎建設與架構
- 技術棧以及技術方案
- 業務目錄大綱
- 前端大綱
- api管理
- 后端api工具
- 前端easymock
- api攔截與代理
- api優化
- api請求時長策略設計
- 前端架構專題
- 架構專題一
- 產品原型對接
- 與ui對接
- 圖片專題
- 圖片工程化大綱
- 圖片優化
- 圖標字體
- 圖標字體vs雪碧圖
- 工程化的前端矩陣
- 螞蟻金服前端矩陣分享
- BFF架構
- 概念解析
- 前端腳手架
- 初始化項目
- 個性化配置
- 部署與發布
- 性能優化專題
- http專題
- https常識
- http優化1
- http優化2
- http優化3
- http緩存
- 常規web性能優化攻略
- 性能優化大綱
- 樣式優化
- js優化
- 第三方依賴優化
- 代碼分割優化
- 圖片優化
- 打包優化
- 服務器優化
- 緩存優化
- 交互優化
- pc事件優化
- 手機事件優化
- 推薦文章
- 01
- 前端安全專題
- 前端安全大綱
- 前端第三方庫
- seo優化
- web框架的對比
- 001
- 學習資源
- 珠峰前端架構
- npm教程
- npm入門
- cnpm入門
- cnpm搭建
- 你該知道的js模塊
- browserSync
- opn
- js-cookie
- npm-script進階
- 入門篇
- 進階篇
- 高階篇
- 實踐篇
- yarn入門
- nodejs教程
- axios&&fetch
- xhr
- axios
- fetch
- babel專題
- babel入門
- profill入門
- nodejs入門
- 快速入門
- 大綱介紹
- node基礎
- global obj
- assert斷言
- procss-進程
- child_process子進程
- cluster集群
- console控制臺
- crypto-加密
- dgram-數據報
- dns-域名服務器
- error-異常
- events-事件
- global-全局變量
- http-基本協議
- https-安全協議
- modules-模塊
- os-操作系統
- path-路徑
- querystring-查詢字符串
- readline-逐行讀取
- fs-文件系統
- net-網絡操作
- 命令行工具
- 內存泄露
- 代碼的組織與部署
- 異步編程
- orm模塊
- 異步編程解決方案
- node-lessons
- 環境準備
- nodejs實踐
- 項目搭建
- 異步優化
- 創建web和tcp服務器
- 終端問答程序
- 爬蟲系統
- mongleDb
- mongoDB簡介
- 基本使用
- 實用技巧
- 匯總001
- 餓了么后臺搭建
- nodejs干貨
- 滬江基于node的實踐
- 蘇寧基于nodejs優化
- 基于nodejs開發腳手架
- 書籍干貨
- 深入淺出nodejs
- 異步I/O(一)
- gulp教程
- gulp入門
- gulp常用插件(1)
- gulp常用插件(2)
- gulp創建目錄
- 經驗普及貼
- webpack教程
- webpack入門
- 簡單入門
- entry配置
- output配置
- 插件使用01
- 插件使用02
- loader使用
- dev-server介紹
- 構建css
- css模塊化
- 使用less和sass
- 構建圖片
- 引入字體
- babel配置攻略
- eslint
- 001
- webpack進階
- 分不同文件檢出
- 優化打包大小
- 優化打包速度
- 自定義配置
- 單頁以及多頁如何配置
- 優化實踐
- 文章導讀
- 001
- 優化指南
- 參考列表
- webpack4
- 多入口程序構建
- 參考教程
- 項目實踐
- 環境區分
- 常見問題
- 解讀webpack
- 從vuejs權威指南中解決
- 深入淺出webpack
- rollup
- 入門
- parcel
- 入門篇
- express教程
- nuxt教程
- 入門
- 基本入門
- koa教程
- koa基本入門
- koa開發注意事項
- koa實踐指南
- 關于路由
- koa優化指南
- 001
- Vuejs
- vuejs入門系列
- vue-cli入門
- vue2基本認識
- vuejs入門教程
- 樣式綁定
- vuex入門學習筆記
- vue組件生命周期
- 組件的使用
- vue-router入門
- vue-filter
- 計算屬性使用
- 開發注意事項
- mixins
- 組件通訊
- vuejs進階
- 進階資源
- router進階
- 官網介紹
- 前進與后退優化
- keep-alive基本使用
- keep-alive原理詳解
- 鉤子函數進階
- 計算屬性&監聽&方法
- vue服務端渲染技術
- 項目實踐之路
- 實踐大綱
- 插槽專題篇
- vue-cli升級
- 進階入門
- vuejs架構
- nuxt
- vuejs項目實踐
- vue實踐常見問題
- 001
- 002
- 003
- 004
- 005
- 改造api參數探索
- 007
- 008
- 009
- 010
- 項目技術棧
- vue性能問題以及優化方案
- vue-spa應用的理解
- vue-ssr的部署與使用
- 滴滴出行實踐案例
- 2.0重構
- vue-element-admin實踐
- 準備工作
- 菜單設計
- 權限設計
- 依賴模塊
- vue-betterScroll
- 性能優化懶加載
- 京東組件實踐
- vue2項目小結
- vue探索與實踐
- 去哪實踐
- 介紹
- 餓了么項目實踐
- 項目解析
- vue骨架屏實踐
- vue生態推薦
- ui框架
- elementUI
- 001
- 002
- VUE-material
- vant-ui
- 解讀入門
- iview
- 使用問題匯總
- vux
- mint-ui
- loadmore
- vue資源導航
- vueconf
- 源碼解讀
- vm
- 雙向綁定
- 基本原理
- 數組雙向綁定
- 報錯機制
- 封裝方法
- 運行環境
- 入門
- 指令
- vue-router解讀
- util
- vue-props
- 流程邏輯
- 推薦文章
- 源碼解讀
- 文章導讀
- 001
- vuejs實戰
- 基礎篇
- 進階篇
- 實踐篇
- 面試專題
- angularjs教程
- angularjs入門系列
- 基本入門
- ng2入門
- ng進階
- ng項目實踐
- 源碼解讀
- typescript
- reactjs教程
- reactjs入門系列
- react的基本入門
- react組件
- virtalDom認識
- react-cli入門
- react組件的生命周期
- 基本知識點
- react-router教程
- react進階
- 基本實踐
- react加載性能優化指南
- react屬性封裝
- 進階45講
- 01概述
- 02jsx
- 06高階組件&函數子組件
- contextApi
- react-router
- 入門章節
- 進階
- 高階組件
- react進階組件
- 基本介紹
- render props
- render props的封裝
- render props getter
- react-native入門
- 源碼解讀
- 001
- 002-reactDemo
- 參考教程
- 參考教程1
- 了解react-hooks
- ui框架
- pc端ui框架推薦
- 項目實踐
- weatherApp
- 001
- 002
- 不同生命周期使用場景
- react項目結構和組件的命名
- 常見問題解答
- 參考書籍
- react全棧
- 前言
- react與redux進階
- 常見誤解
- 反模式
- react設計模式與最佳實踐
- 7美化組件
- 7.2行內樣式
- 7.4css模塊
- 深入react技術棧
- react學習手冊
- 序
- mobx教程
- 入門
- 大佬推薦
- 001
- react面試
- 001
- linux教程
- linux入門
- 基本入門
- 文件管理
- 文件傳輸
- 文檔編輯
- 磁盤管理
- 磁盤維護
- 網絡通訊
- 系統管理
- 系統設置
- 備份壓縮
- 設備管理
- 查看系統信息
- linux其他
- webhook
- rsync入門教程
- ssh免登陸設置
- 安裝nodejs
- nginx教程
- 入門教程
- 安裝
- 基本配置
- 服務基本使用
- 高性能nginx
- 001
- pm2教程
- shell教程
- 入門大綱
- echo命令
- 參考文獻
- linux常用命令2
- linux常見問題
- 001
- python
- 入門教程
- 機器學習
- 準備工作
- 服務器常識
- tomcat
- 入門常識
- iis
- redis教程
- 入門第一篇
- redis進階
- 項目實踐
- redis使用問題
- mongleDB
- 入門
- 使用進階
- 項目實踐
- 常見問題
- electron
- 入門系列
- 前言
- 小程序
- 入門
- 準備工作
- 路由
- 參考文檔
- 001
- 小程序開發--雙路視頻調研
- 準備工作
- 參考資源
- 參考網址
- docker
- 入門
- 基本認識
- 安裝與使用
- docker安裝nginx
- docker安裝jetkins(1)
- docker部署jenkins(2)
- 進階
- 實踐總結
- docker群分享
- docker部署前端應用
- 文章導讀
- docker其他
- 網絡安全
- 入門
- 大綱
- 項目解析
- schoolpal.web
- 功能模塊大綱
- 目錄結構大綱
- 前端國際化
- 國際化方案
- 其他
- bower入門教程
- weex
- 入門
- memcached
- 入門
- sails
- 入門