Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
How to walk in the Crowi
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Norio Suzuki
November 03, 2016
Programming
16k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
How to walk in the Crowi
How to walk in the Crowi / Crowi の歩き方
at PHP Conference 2016
http://phpcon.php.gr.jp/2016/
Norio Suzuki
November 03, 2016
More Decks by Norio Suzuki
See All by Norio Suzuki
リーダブル プルリクエスト 分割プルリクエスト編 / Readable Pull Request
suzuki
3
2.2k
ふんわり使うPlantUML
suzuki
0
1.5k
Symfony Serializer Deep Dive
suzuki
0
2.4k
Swift Mailer Update
suzuki
2
2.6k
Guzzle Promiseを使った 非同期処理によるAPIコールの高速化
suzuki
15
17k
PHP BLT #4
suzuki
1
5.2k
Learning Swift2 with PHP7
suzuki
2
4.3k
ポモドーロ・テクニック入門の入門
suzuki
0
770
Automatically run the JavaScript test in multiple browsers
suzuki
5
6.5k
Other Decks in Programming
See All in Programming
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
190
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
340
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
280
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
560
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
380
Workers Cache を知る
syumai
0
310
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
180
iOSDCのペンライトを自動制御したい!
akkeylab
0
140
難しいけど、読めた。- OSSの入口に立った話。
sts11142
0
130
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
440
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
980
wkhtmltopdfの次どうするか問題2026
willnet
2
1.8k
Featured
See All Featured
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
290
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
The Pragmatic Product Professional
lauravandoore
37
7.5k
Typedesign – Prime Four
hannesfritz
42
3.2k
WENDY [Excerpt]
tessaabrams
14
39k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
540
The World Runs on Bad Software
bkeepers
PRO
72
12k
The SEO identity crisis: Don't let AI make you average
varn
0
560
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
66k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Making Projects Easy
brettharned
120
6.8k
Transcript
How to walk in the Crowi ʙ How PHPer developed
the product of Node.js ʙ PHP Conference 2016 (Tokyo) 2016-11-03 @suzuki
Crowi ͷา͖ํ ʙPHPer ͕ Node.js ͷϓϩμΫτΛ৮ΔΑ͏ʹͳΔ·Ͱʙ PHP Conference 2016 (Tokyo)
2016-11-03 @suzuki
About me
Twitter: @suzuki GitHub: @suzuki
PHP Conference Fukuoka 2016 https://speakerdeck.com/suzuki/guzzle-promisewoshi-tuta-fei-tong-qi-chu-li-niyoruapikorufalsegao-su-hua
PHP Conference Kansai 2016 https://speakerdeck.com/suzuki/swift-mailer-update
Contributor of Crowi https://github.com/crowi/crowi/graphs/contributors
What is Crowi?
Crowi http://site.crowi.wiki/
Features ɾ Wiki ɾ Markdown ɾ Realtime preview ɾ Login
by Google Account ɾ Notification to Slack
GitHub: crowi/crowi https://github.com/crowi/crowi
More information https://medium.com/crowi-book
More information https://speakerdeck.com/sotarok/crowi
Why am I started to develop the Crowi?
When the year-end party in 2015
Talk about "esa.io" I like "esa.io". I love their Markdown
helper. OK. You create it. I want to use that helper on Crowi. esa logo : https://docs.esa.io/posts/125
He is product founder of Crowi https://github.com/crowi/crowi/graphs/contributors
I tried to implement
Pull request https://github.com/crowi/crowi/pull/38
Pull request https://github.com/crowi/crowi/pull/38
This is my opportunity to develop the Crowi
Crowi overview
System Diagram .POHP%# &MBTUJDTFBSDI 3FEJT "NB[PO4 4MBDL 3FRVJSF 0QUJPOBM Remote
Notification Full text search Data Store Session Data File upload <$SPXJ> /PEFKT (PPHMF Social Login
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Inside Crowi /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS
K2VFSZ 3FBDU #PPUTUSBQ
How to develop?
Install and Configuration https://github.com/crowi/crowi/wiki/Install-and-Configuration
or
GitHub: suzuki/crowi-develop https://github.com/suzuki/crowi-develop
What is "crowi-develop" ɾ Setup Docker containers ɾMongoDB ɾRedis ɾElasticsearch
ɾ Require ɾNode.js ɾDocker for Mac
What is "suzuki/crowi-develop" .POHP%# &MBTUJDTFBSDI 3FEJT "NB[PO4 4MBDL 3FRVJSF 0QUJPOBM
<$SPXJ> /PEFKT (PPHMF Prepare these
How to initialize "crowi-develop"
Clone "crowi-develop" repository $ git clone https://github.com/suzuki/crowi-develop
Clone "crowi" repository $ cd crowi-develop $ git clone
[email protected]
:crowi/crowi.git
Files in "crowi-develop" LICENSE README.md crowi/ data/ docker-compose.yml Crowi directory
Data directory for Docker containers
Run Docker containers $ cd crowi-develop $ docker-compose up -d
Run Crowi $ cd crowi-develop/crowi $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi
\ ELASTICSEARCH_URI=localhost:9200 \ REDIS_URL=localhost \ FILE_UPLOAD=local \ node app.js Change your own word
Open localhost:3000 http://localhost:3000/
Create administrator http://localhost:3000/installer
Open administration menu http://localhost:3000/ Administration menu
Open search menu http://localhost:3000/admin Search menu
Build search index http://localhost:3000/admin/search Build index
Daily routine: start up "crowi-develop"
Run Docker container $ cd crowi-develop $ docker-compose up -d
Run Crowi $ cd crowi-develop/crowi $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi
\ ELASTICSEARCH_URI=localhost:9200 \ REDIS_URL=localhost \ FILE_UPLOAD=local \ node app.js Change your own word
Daily routine: shutdown "crowi-develop"
Shutdown Crowi $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi \ ELASTICSEARCH_URI=localhost:9200 \
REDIS_URL=localhost \ FILE_UPLOAD=local \ node app.js Press Ctrl + C
Shutdown Docker container $ docker-compose stop
Case study: I want to modify…
I want to modify CSS
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF CSS /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS K2VFSZ
3FBDU #PPUTUSBQ
Keywords of using tools ɾ Bootstrap ɾ Sass ɾ Gulp
Go to directory $ cd crowi/resource/css/
Modify files $ ls -1F _admin.scss _comment.scss _form.scss _layout.scss _mixins.scss
_page.scss _page_list.scss _portal.scss _search.scss _user.scss _utilities.scss _variables.scss _wiki.scss crowi-reveal.scss crowi.scss "_NAME.scss" are component "crowi.scss" is main file
Build $ ./node_modules/.bin/gulp css
Check result ɾ Reload your browser
Watch files $ ./node_modules/.bin/gulp watch
I want to modify HTML
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF HTML (Template) /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS
K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ Swig
Swig: template engine https://www.npmjs.com/package/swig
Format sample <h1>{{ pagename }}</h1> <ul> {% for author in
authors %} <li>{{ author }}</li> {% endfor %} </ul> variable name for loop
Swig is similar to the Twig http://twig.sensiolabs.org/
Go to directory $ cd crowi/lib/views/
Modify files $ ls -1F 500.html _form.html admin/ index.html installer.html
invited.html layout/ login/ login.html mail/ me/ modal/ page.html page_list.html page_presentation.html search.html user/ user_page.html widget/ "*.html" are template of Swig
Build Nothing to do
Check result ɾ Restart Crowi ɾ Reload your browser
I want to modify Front-end JavaScript
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Front-end JavaScript /PEFKT &YQSFTT .POHPPTF 4XJH #SPXTFS
K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ jQuery
Go to directory $ cd crowi/resource/js/
Modify files $ ls -1F app.js components/ crowi-admin.js crowi-form.js crowi-presentation.js
crowi.js util/
Build $ ./node_modules/.bin/gulp [dev]
I want to modify Front-end JavaScript (React)
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Front-end JavaScript (React) /PEFKT &YQSFTT .POHPPTF 4XJH
#SPXTFS K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ Swig ɾ React
Our future plan: Use React more
Go to directory $ cd crowi/resource/js/
Modify files $ ls -1F app.js components/ crowi-admin.js crowi-form.js crowi-presentation.js
crowi.js util/ React components ReactDOM.render()
Modify files (components) $ ls -1F components/ HeaderSearchBox/ HeaderSearchBox.js Page/
PageList/ PageListSearch.js SearchPage/ SearchPage.js User/
Modify Template 4XJH5FNQMBUF EJWJE40.&@*%@'03@3&/%&3EJW React component will render here
Modify React renderer (in app.js) const componentMappings = { 'search-top':
<HeaderSearchBox />, 'search-page': <SearchPage />, 'page-list-search': <PageListSearch />, }; Object.keys(componentMappings).forEach((key) => { const elem = document.getElementById(key); if (elem) { ReactDOM.render(componentMappings[key], elem); } }); DOM id (in Swig template)
Similar case http://techlife.cookpad.com/entry/2016/10/26/135818
Build $ ./node_modules/.bin/gulp [dev]
Check result ɾ Restart Crowi ɾif you modified template ɾ
Reload your browser
I want to add Some New feature
<$SPXJ> $MJFOU4JEF 4FSWFS4JEF Some new feature (server side) /PEFKT &YQSFTT
.POHPPTF 4XJH #SPXTFS K2VFSZ 3FBDU #PPUTUSBQ
Keywords of using tools ɾ Express ɾ Mongoose ɾ Swig
MVC of Crowi .PEFM .POHPPTF 7JFX 4XJH 3FBDU $POUSPMMFS &YQSFTT
$POUSPMMFS .PEFM Request flow SPVUFTJOEFYKT SPVUFT3065&@KT NPEFMT.0%&-@KT Request NPEFMT.0%&-@KT NPEFMT.0%&-@OKT
SPVUFT3065&@KT SPVUFT3065&@OKT
Controller: Express
Express http://expressjs.com/
Go to directory $ cd crowi/lib/routes/
Modify files $ ls -1F admin.js attachment.js bookmark.js comment.js index.js
installer.js login.js logout.js me.js page.js revision.js search.js user.js
Router: index.js
Router (index.js) var page = require('./page')(crowi, app); var middleware =
require('../util/middlewares'); var loginRequired = middleware.loginRequired; app.get('/*/$', loginRequired(crowi, app), page.pageListShow); app.get('/*', loginRequired(crowi, app), page.pageShow); HTTP method Request path Router (Controller) method
page.pageShow (page.js) actions.pageShow = function(req, res) { var path =
path || getPathFromRequest(req); Page.findPage(path, req.user, req.query.revision) .then(function(page) { // some routines return renderPage(page, req, res); }).catch(function(err) { // not found }); }; Page model method
Model: Mongoose
Mongoose http://mongoosejs.com/
Go to directory $ cd crowi/lib/models/
Modify files $ ls -1F attachment.js bookmark.js comment.js config.js index.js
page.js revision.js updatePost.js user.js
DB Schema (page.js) pageSchema = new mongoose.Schema({ path: {type: String,
required: true, index: true, unique: true}, revision: {type: ObjectId, ref: 'Revision'}, status: {type: String, default: STATUS_PUBLISHED, index: true}, creator: {type: ObjectId, ref: 'User', index: true}, createdAt: {type: Date, default: Date.now}, }
Sample Data
Sample page Page + Revision data
"path" field: String pageSchema = new mongoose.Schema({ path: {type: String,
required: true, index: true, unique: true}, revision: {type: ObjectId, ref: 'Revision'}, status: {type: String, default: STATUS_PUBLISHED, index: true}, creator: {type: ObjectId, ref: 'User', index: true}, createdAt: {type: Date, default: Date.now}, } type: String
"path" field data { "_id": ObjectId("580fe42645419f6dcf5f4c49"), "path": "/user/suzuki/memo/2016/10/26/test_page", "revision": ObjectId("580fe42645419f6dcf5f4c4a")
"status": "published", "creator": ObjectId("580401458462d38221a37094"), "createdAt": ISODate("2016-10-25T23:00:54.020Z"), } String data
"revision" field: ObjectId pageSchema = new mongoose.Schema({ path: {type: String,
required: true, index: true, unique: true}, revision: {type: ObjectId, ref: 'Revision'}, status: {type: String, default: STATUS_PUBLISHED, index: true}, creator: {type: ObjectId, ref: 'User', index: true}, createdAt: {type: Date, default: Date.now}, } type: ObjectId ref: 'Revision'
"revision" field data { "_id": ObjectId("580fe42645419f6dcf5f4c49"), "path": "/user/suzuki/memo/2016/10/26/test_page", "revision": ObjectId("580fe42645419f6dcf5f4c4a")
"status": "published", "creator": ObjectId("580401458462d38221a37094"), "createdAt": ISODate("2016-10-25T23:00:54.020Z"), } This means reference 'Revision'
Revision data { "_id": ObjectId("580fe42645419f6dcf5f4c4a"), "author": ObjectId("580401458462d38221a37094"), "body": "# test_page\r\n\r\nThis
is a test page.\r\n", "path": "/user/suzuki/memo/2016/10/26/test_page", }
Schema types of Mongoose ɾ String ɾ Number ɾ Date
ɾ Buffer ɾ Boolean ɾ Mixed ɾ ObjectId ɾ Array MongoDB is schema-less, But, Mongoose has schema types
Method (page.js) // find page and check if granted user
pageSchema.statics.findPage = function(path, userData, revisionId, ignoreNotFound) { var self = this; return new Promise(function(resolve, reject) { self.findOne({path: path}, function(err, pageData) { if (err) { return reject(err); } if (pageData === null) { if (ignoreNotFound) { return resolve(null); } var pageNotFoundError = new Error('Page Not Found') pageNotFoundError.name = 'Crowi:Page:NotFound'; return reject(pageNotFoundError); } // snip
View: Swig + React
See CSS, Front-end JS page
How to debug
Debug log
var debug = require('debug')('crowi:routes:page'); Define debug (routes/page.js) Key name
actions.pageListShow = function(req, res) { var path = getPathFromRequest(req); debug('Page
list show', path); Call debug (routes/page.js) No output by default
Run Crowi with DEBUG environment $ PASSWORD_SEED=somesecretstring \ MONGO_URI=mongodb://localhost/crowi
\ ELASTICSEARCH_URI=localhost:9200 \ REDIS_URL=localhost \ FILE_UPLOAD=local \ DEBUG=crowi:routes:page \ node app.js Set DEBUG env.
Run Crowi with DEBUG environment [development] Express server listening on
port 3000 crowi:routes:page Page list show +0ms / Debug log
lib/routes/page.js: var debug = require('debug')('crowi:routes:page'); lib/routes/revision.js: var debug = require('debug')('crowi:routes:revision');
lib/models/page.js: var debug = require('debug')('crowi:models:page'); lib/models/comment.js: var debug = require('debug')('crowi:models:comment'); Wildcard DEBUG env. DEBUG=crowi:models:*
More information about DEBUG ɾ Debugging Express ɾ http://expressjs.com/en/guide/debugging.html (English)
ɾ http://expressjs.com/ja/guide/debugging.html (Japanese)
View data
Get container name MondoDB container name is here. For this
example, "crowidevelop_mongodb_1"
Login container $ docker exec -it crowidevelop_mongodb_1 /bin/bash Execute "/bin/bash"
in container
Run mongo CLI root@f7e7c8334c37:/# mongo MongoDB shell version: 3.2.9 connecting
to: local >
Select database > use crowi switched to db crowi
Show collections (SHOW TABLES) > show collections attachments bookmarks comments
configs pages revisions updateposts users Collections are mapped to Models
Find data (SELECT data) > db.pages.find(); SELECT * FROM pages;
Find data: WHERE Clause > db.pages.find({"_id": ObjectId("580fe42645419f6dcf5f4c49")}); SELECT * FROM
pages WHERE _id = ObjectId("580fe42645419f6dcf5f4c49")
find() > db.pages.find(); { "_id" : ObjectId("580fe42645419f6dcf5f4c49"), "redirectTo" : null,
"updatedAt" : ISODate("2016-10-25T23:00:54.091Z"), "lastUpdateUser" : ObjectId("580401458462d38221a37094"), "creator" : ObjectId("580401458462d38221a37094"), "path" : "/ user/suzuki/memo/2016/10/26/test_page", "createdAt" : ISODate("2016-10-25T23:00:54.020Z"), "extended" : "{}", "commentCount" : 1, "seenUsers" : [ ObjectId("580401458462d38221a37094") ], "liker" : [ ], "grantedUsers" : [ ObjectId("580401458462d38221a37094") ], "grant" : 1, "status" : "published", "__v" : 1, "revision" : ObjectId("580fe42645419f6dcf5f4c4a") }
find().pretty() > db.pages.find().pretty(); { "_id" : ObjectId("580fe42645419f6dcf5f4c49"), "redirectTo" : null,
"updatedAt" : ISODate("2016-10-25T23:00:54.091Z"), "lastUpdateUser" : ObjectId("580401458462d38221a37094"), "creator" : ObjectId("580401458462d38221a37094"), "path" : "/user/suzuki/memo/2016/10/26/test_page", "createdAt" : ISODate("2016-10-25T23:00:54.020Z"), "extended" : "{}", "commentCount" : 1, // snip "status" : "published", "revision" : ObjectId("580fe42645419f6dcf5f4c4a") }
More information about MongoDB ɾ The mongo Shell ɾ https://docs.mongodb.com/v3.2/mongo/
ɾ GUI ɾ https://docs.mongodb.com/ecosystem/tools/administration-interfaces/
How to Test?
Run tests $ ./node_modules/.bin/gulp test OR $ MONGO_URI=localhost:crowi_test \ ./node_modules/.bin/gulp
test "crowi_test" DB is used "crowi" (default) DB is used I recommend to use different name from "crowi"
Files $ cd crowi/tests/ $ ls -1F bootstrap.js crowi/ models/
util/ utils.js
Problems ɾ Coverage ɾ We have little tests... ɾ No
View test ɾ React component tests? ɾ E2E tests?
Conclusion
Crowi is a growing software ɾ Crowi is very simple
and useful ɾ Growing software ɾ We are using the Crowi in our company ɾ When received feedback, we will fixed that problem or create new features ɾ Try to use the Crowi in your organization
We learned first-step to develop Crowi ɾ Today, we have
learned how to develop the Crowi ɾ You can use your experience in PHP ɾ It is not difficult to develop
Today's theme http://phpcon.php.gr.jp/2016/
Next Action: Contribute! ɾ Code for Crowi ɾ Pull Request,
Issue, Document, etc. ɾ Talk about Crowi ɾ Gitter, Twitter, Facebook, Blog, etc. ɾ #crowi in Twitter ɾ Gitter: https://gitter.im/crowi/general
And, we are hiring! https://www.mercari.com/jp/jobs/ But, a full-time Crowi job
is not exist
Thank you
Appendix
Appendix ɾ Crowi ɾ https://github.com/crowi/crowi ɾ Crowi develop ɾ https://github.com/suzuki/crowi-develop
ɾ Crowi book (blog) ɾ https://medium.com/crowi-book ɾ Crowi gitter ɾ https://gitter.im/crowi/general