VOTING POWER100.00%
DOWNVOTE POWER100.00%
RESOURCE CREDITS100.00%
REPUTATION PROGRESS0.00%
Net Worth
0.025USD
STEEM
0.003STEEM
SBD
0.036SBD
Effective Power
5.007SP
├── Own SP
0.125SP
└── Incoming DelegationsDeleg
+4.882SP
Detailed Balance
| STEEM | ||
| balance | 0.000STEEM | STEEM |
| market_balance | 0.000STEEM | STEEM |
| savings_balance | 0.000STEEM | STEEM |
| reward_steem_balance | 0.003STEEM | STEEM |
| STEEM POWER | ||
| Own SP | 0.125SP | SP |
| Delegated Out | 0.000SP | SP |
| Delegation In | 4.882SP | SP |
| Effective Power | 5.007SP | SP |
| Reward SP (pending) | 0.020SP | SP |
| SBD | ||
| sbd_balance | 0.000SBD | SBD |
| sbd_conversions | 0.000SBD | SBD |
| sbd_market_balance | 0.000SBD | SBD |
| savings_sbd_balance | 0.000SBD | SBD |
| reward_sbd_balance | 0.036SBD | SBD |
{
"balance": "0.000 STEEM",
"savings_balance": "0.000 STEEM",
"reward_steem_balance": "0.003 STEEM",
"vesting_shares": "203.852317 VESTS",
"delegated_vesting_shares": "0.000000 VESTS",
"received_vesting_shares": "7939.807489 VESTS",
"sbd_balance": "0.000 SBD",
"savings_sbd_balance": "0.000 SBD",
"reward_sbd_balance": "0.036 SBD",
"conversions": []
}Account Info
| name | mnkim |
| id | 937523 |
| rank | 316,037 |
| reputation | 454084791 |
| created | 2018-04-12T00:47:48 |
| recovery_account | steem |
| proxy | None |
| post_count | 4 |
| comment_count | 0 |
| lifetime_vote_count | 0 |
| witnesses_voted_for | 0 |
| last_post | 2018-06-06T13:57:09 |
| last_root_post | 2018-06-05T09:08:06 |
| last_vote_time | 2018-06-06T13:57:15 |
| proxied_vsf_votes | 0, 0, 0, 0 |
| can_vote | 1 |
| voting_power | 0 |
| delayed_votes | 0 |
| balance | 0.000 STEEM |
| savings_balance | 0.000 STEEM |
| sbd_balance | 0.000 SBD |
| savings_sbd_balance | 0.000 SBD |
| vesting_shares | 203.852317 VESTS |
| delegated_vesting_shares | 0.000000 VESTS |
| received_vesting_shares | 7939.807489 VESTS |
| reward_vesting_balance | 40.655714 VESTS |
| vesting_balance | 0.000 STEEM |
| vesting_withdraw_rate | 0.000000 VESTS |
| next_vesting_withdrawal | 1969-12-31T23:59:59 |
| withdrawn | 0 |
| to_withdraw | 0 |
| withdraw_routes | 0 |
| savings_withdraw_requests | 0 |
| last_account_recovery | 1970-01-01T00:00:00 |
| reset_account | null |
| last_owner_update | 1970-01-01T00:00:00 |
| last_account_update | 1970-01-01T00:00:00 |
| mined | No |
| sbd_seconds | 0 |
| sbd_last_interest_payment | 1970-01-01T00:00:00 |
| savings_sbd_last_interest_payment | 1970-01-01T00:00:00 |
{
"id": 937523,
"name": "mnkim",
"owner": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM83T3qMZ6smHSVkVu9bzsfZYmkuB8HTr7UaPBhCd2jcAcX1xxAC",
1
]
]
},
"active": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM85PsTh3MXSxG8hspgT4LoQrpayLqHiMSRGFVufs9rnY5cAi1VZ",
1
]
]
},
"posting": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM6adjVawMAg7bnZaGoxxqs2CEQdq16HvpAcfrhZ7PWtAdQpRVRb",
1
]
]
},
"memo_key": "STM7NCpqSwzRLX8fCWvoyCaLsVCBBbLEYoiJA9vtFk4KKemk1BitM",
"json_metadata": "{}",
"posting_json_metadata": "",
"proxy": "",
"last_owner_update": "1970-01-01T00:00:00",
"last_account_update": "1970-01-01T00:00:00",
"created": "2018-04-12T00:47:48",
"mined": false,
"recovery_account": "steem",
"last_account_recovery": "1970-01-01T00:00:00",
"reset_account": "null",
"comment_count": 0,
"lifetime_vote_count": 0,
"post_count": 4,
"can_vote": true,
"voting_manabar": {
"current_mana": "8143659806",
"last_update_time": 1779076533
},
"downvote_manabar": {
"current_mana": 2035914951,
"last_update_time": 1779076533
},
"voting_power": 0,
"balance": "0.000 STEEM",
"savings_balance": "0.000 STEEM",
"sbd_balance": "0.000 SBD",
"sbd_seconds": "0",
"sbd_seconds_last_update": "1970-01-01T00:00:00",
"sbd_last_interest_payment": "1970-01-01T00:00:00",
"savings_sbd_balance": "0.000 SBD",
"savings_sbd_seconds": "0",
"savings_sbd_seconds_last_update": "1970-01-01T00:00:00",
"savings_sbd_last_interest_payment": "1970-01-01T00:00:00",
"savings_withdraw_requests": 0,
"reward_sbd_balance": "0.036 SBD",
"reward_steem_balance": "0.003 STEEM",
"reward_vesting_balance": "40.655714 VESTS",
"reward_vesting_steem": "0.020 STEEM",
"vesting_shares": "203.852317 VESTS",
"delegated_vesting_shares": "0.000000 VESTS",
"received_vesting_shares": "7939.807489 VESTS",
"vesting_withdraw_rate": "0.000000 VESTS",
"next_vesting_withdrawal": "1969-12-31T23:59:59",
"withdrawn": 0,
"to_withdraw": 0,
"withdraw_routes": 0,
"curation_rewards": 0,
"posting_rewards": 39,
"proxied_vsf_votes": [
0,
0,
0,
0
],
"witnesses_voted_for": 0,
"last_post": "2018-06-06T13:57:09",
"last_root_post": "2018-06-05T09:08:06",
"last_vote_time": "2018-06-06T13:57:15",
"post_bandwidth": 0,
"pending_claimed_accounts": 0,
"vesting_balance": "0.000 STEEM",
"reputation": 454084791,
"transfer_history": [],
"market_history": [],
"post_history": [],
"vote_history": [],
"other_history": [],
"witness_votes": [],
"tags_usage": [],
"guest_bloggers": [],
"rank": 316037
}Withdraw Routes
| Incoming | Outgoing |
|---|---|
Empty | Empty |
{
"incoming": [],
"outgoing": []
}From Date
To Date
2026/05/18 03:55:33
2026/05/18 03:55:33
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 7939.807489 VESTS |
| Transaction Info | Block #106147834/Trx b73a78f806b8b6e66a121e39020169e6d5e405ab |
View Raw JSON Data
{
"block": 106147834,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "7939.807489 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2026-05-18T03:55:33",
"trx_id": "b73a78f806b8b6e66a121e39020169e6d5e405ab",
"trx_in_block": 3,
"virtual_op": 0
}2026/05/12 18:43:09
2026/05/12 18:43:09
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 5227.597084 VESTS |
| Transaction Info | Block #105993526/Trx 0491263b8dfbdfc857f7eb26b46d87c1fa5f41a8 |
View Raw JSON Data
{
"block": 105993526,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "5227.597084 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2026-05-12T18:43:09",
"trx_id": "0491263b8dfbdfc857f7eb26b46d87c1fa5f41a8",
"trx_in_block": 0,
"virtual_op": 0
}2026/04/26 03:10:42
2026/04/26 03:10:42
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 7952.323245 VESTS |
| Transaction Info | Block #105515382/Trx d3807cb171dc9272dfc88ba2ed47642fda01cba4 |
View Raw JSON Data
{
"block": 105515382,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "7952.323245 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2026-04-26T03:10:42",
"trx_id": "d3807cb171dc9272dfc88ba2ed47642fda01cba4",
"trx_in_block": 2,
"virtual_op": 0
}2026/01/23 17:39:03
2026/01/23 17:39:03
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 5269.143903 VESTS |
| Transaction Info | Block #102863612/Trx b4ef1ff622f10a1e8fadbbd54f72a755ff390e3d |
View Raw JSON Data
{
"block": 102863612,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "5269.143903 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2026-01-23T17:39:03",
"trx_id": "b4ef1ff622f10a1e8fadbbd54f72a755ff390e3d",
"trx_in_block": 26,
"virtual_op": 0
}2024/12/17 12:51:36
2024/12/17 12:51:36
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 5433.363100 VESTS |
| Transaction Info | Block #91309876/Trx 272179fb15a972a011bd1c34c86d12009dbcb3fa |
View Raw JSON Data
{
"block": 91309876,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "5433.363100 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2024-12-17T12:51:36",
"trx_id": "272179fb15a972a011bd1c34c86d12009dbcb3fa",
"trx_in_block": 2,
"virtual_op": 0
}2023/11/14 04:33:18
2023/11/14 04:33:18
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 5602.496632 VESTS |
| Transaction Info | Block #79864047/Trx deb37ed2f19cec860f5d11ee8276269533198a95 |
View Raw JSON Data
{
"block": 79864047,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "5602.496632 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2023-11-14T04:33:18",
"trx_id": "deb37ed2f19cec860f5d11ee8276269533198a95",
"trx_in_block": 0,
"virtual_op": 0
}2023/09/22 07:35:15
2023/09/22 07:35:15
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 8539.405418 VESTS |
| Transaction Info | Block #78359511/Trx 51a333aeded4488d3f4a01853b313224f0b756fa |
View Raw JSON Data
{
"block": 78359511,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "8539.405418 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2023-09-22T07:35:15",
"trx_id": "51a333aeded4488d3f4a01853b313224f0b756fa",
"trx_in_block": 1,
"virtual_op": 0
}2022/11/03 15:24:51
2022/11/03 15:24:51
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 8761.456856 VESTS |
| Transaction Info | Block #69117692/Trx 611b08d34efe1c47e683c153f5a4b1423bfd95e9 |
View Raw JSON Data
{
"block": 69117692,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "8761.456856 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2022-11-03T15:24:51",
"trx_id": "611b08d34efe1c47e683c153f5a4b1423bfd95e9",
"trx_in_block": 1,
"virtual_op": 0
}2022/01/17 20:50:39
2022/01/17 20:50:39
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 8981.564457 VESTS |
| Transaction Info | Block #60821218/Trx 6194343692cd55b568a8d3d74373ee30fffa1966 |
View Raw JSON Data
{
"block": 60821218,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "8981.564457 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2022-01-17T20:50:39",
"trx_id": "6194343692cd55b568a8d3d74373ee30fffa1966",
"trx_in_block": 7,
"virtual_op": 0
}2021/06/14 04:07:51
2021/06/14 04:07:51
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 9165.758745 VESTS |
| Transaction Info | Block #54611677/Trx 4c1c93674c6fde63dbaba500a57f31b02b3a5283 |
View Raw JSON Data
{
"block": 54611677,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "9165.758745 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2021-06-14T04:07:51",
"trx_id": "4c1c93674c6fde63dbaba500a57f31b02b3a5283",
"trx_in_block": 10,
"virtual_op": 0
}2020/12/11 14:22:27
2020/12/11 14:22:27
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 9353.180719 VESTS |
| Transaction Info | Block #49359010/Trx 7a2217a72053e384b94756c7b9fdf19db8d1f12d |
View Raw JSON Data
{
"block": 49359010,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "9353.180719 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2020-12-11T14:22:27",
"trx_id": "7a2217a72053e384b94756c7b9fdf19db8d1f12d",
"trx_in_block": 4,
"virtual_op": 0
}2020/12/06 07:58:21
2020/12/06 07:58:21
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 1912.543513 VESTS |
| Transaction Info | Block #49210541/Trx 5e838046b56667e5ff513ea3dabc7c3bf5067e16 |
View Raw JSON Data
{
"block": 49210541,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "1912.543513 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2020-12-06T07:58:21",
"trx_id": "5e838046b56667e5ff513ea3dabc7c3bf5067e16",
"trx_in_block": 3,
"virtual_op": 0
}2020/12/05 18:00:06
2020/12/05 18:00:06
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 9359.388573 VESTS |
| Transaction Info | Block #49194093/Trx 832654d4ff5c8faf5402011e7270b589f7b08252 |
View Raw JSON Data
{
"block": 49194093,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "9359.388573 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2020-12-05T18:00:06",
"trx_id": "832654d4ff5c8faf5402011e7270b589f7b08252",
"trx_in_block": 0,
"virtual_op": 0
}2020/11/02 22:22:03
2020/11/02 22:22:03
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 1920.017158 VESTS |
| Transaction Info | Block #48265727/Trx 6d15cf57871fb00104c2c9871189ca521fc10ba3 |
View Raw JSON Data
{
"block": 48265727,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "1920.017158 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2020-11-02T22:22:03",
"trx_id": "6d15cf57871fb00104c2c9871189ca521fc10ba3",
"trx_in_block": 5,
"virtual_op": 0
}2020/05/09 08:59:30
2020/05/09 08:59:30
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 9562.193932 VESTS |
| Transaction Info | Block #43220844/Trx 00421f559f9bcaa9d8a9e157b4238b00e6e8d606 |
View Raw JSON Data
{
"block": 43220844,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "9562.193932 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2020-05-09T08:59:30",
"trx_id": "00421f559f9bcaa9d8a9e157b4238b00e6e8d606",
"trx_in_block": 2,
"virtual_op": 0
}2020/05/08 13:05:15
2020/05/08 13:05:15
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 1953.311140 VESTS |
| Transaction Info | Block #43197525/Trx 4db2b891015860dded7090ae0e4aca7e1bc7e1c4 |
View Raw JSON Data
{
"block": 43197525,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "1953.311140 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2020-05-08T13:05:15",
"trx_id": "4db2b891015860dded7090ae0e4aca7e1bc7e1c4",
"trx_in_block": 19,
"virtual_op": 0
}2019/08/19 22:06:30
2019/08/19 22:06:30
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 9712.126504 VESTS |
| Transaction Info | Block #35700268/Trx 9fa260431fe1c01b4563372e58c2adba371b13a2 |
View Raw JSON Data
{
"block": 35700268,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "9712.126504 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2019-08-19T22:06:30",
"trx_id": "9fa260431fe1c01b4563372e58c2adba371b13a2",
"trx_in_block": 16,
"virtual_op": 0
}2019/04/12 02:06:36
2019/04/12 02:06:36
| author | steemitboard |
| body | Congratulations @mnkim! You received a personal award! <table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@mnkim/birthday1.png</td><td>Happy Birthday! - You are on the Steem blockchain for 1 year!</td></tr></table> <sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@mnkim) and compare to others on the [Steem Ranking](http://steemitboard.com/ranking/index.php?name=mnkim)_</sub> ###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes! |
| json metadata | {"image":["https://steemitboard.com/img/notify.png"]} |
| parent author | mnkim |
| parent permlink | angular-route |
| permlink | steemitboard-notify-mnkim-20190412t020636000z |
| title | |
| Transaction Info | Block #31967834/Trx 5b940332d18359a01cf74514c460afd0cb318739 |
View Raw JSON Data
{
"block": 31967834,
"op": [
"comment",
{
"author": "steemitboard",
"body": "Congratulations @mnkim! You received a personal award!\n\n<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@mnkim/birthday1.png</td><td>Happy Birthday! - You are on the Steem blockchain for 1 year!</td></tr></table>\n\n<sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@mnkim) and compare to others on the [Steem Ranking](http://steemitboard.com/ranking/index.php?name=mnkim)_</sub>\n\n\n###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!",
"json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}",
"parent_author": "mnkim",
"parent_permlink": "angular-route",
"permlink": "steemitboard-notify-mnkim-20190412t020636000z",
"title": ""
}
],
"op_in_trx": 0,
"timestamp": "2019-04-12T02:06:36",
"trx_id": "5b940332d18359a01cf74514c460afd0cb318739",
"trx_in_block": 15,
"virtual_op": 0
}2018/09/05 16:17:09
2018/09/05 16:17:09
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 9910.468788 VESTS |
| Transaction Info | Block #25698142/Trx 51a359b6ef8de7a3bff95a91514232faa311b111 |
View Raw JSON Data
{
"block": 25698142,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "9910.468788 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2018-09-05T16:17:09",
"trx_id": "51a359b6ef8de7a3bff95a91514232faa311b111",
"trx_in_block": 11,
"virtual_op": 0
}2018/08/16 23:34:57
2018/08/16 23:34:57
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 30171.251422 VESTS |
| Transaction Info | Block #25131195/Trx d6b4339f8b3dcaa332d0682cfb6649e3e47f8dca |
View Raw JSON Data
{
"block": 25131195,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "30171.251422 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2018-08-16T23:34:57",
"trx_id": "d6b4339f8b3dcaa332d0682cfb6649e3e47f8dca",
"trx_in_block": 10,
"virtual_op": 0
}mnkimreceived 0.003 STEEM, 0.022 SBD, 0.019 SP author reward for @mnkim / angular-route2018/06/12 09:08:06
mnkimreceived 0.003 STEEM, 0.022 SBD, 0.019 SP author reward for @mnkim / angular-route
2018/06/12 09:08:06
| author | mnkim |
| permlink | angular-route |
| sbd payout | 0.022 SBD |
| steem payout | 0.003 STEEM |
| vesting payout | 30.480632 VESTS |
| Transaction Info | Block #23252940/Virtual Operation #13 |
View Raw JSON Data
{
"block": 23252940,
"op": [
"author_reward",
{
"author": "mnkim",
"permlink": "angular-route",
"sbd_payout": "0.022 SBD",
"steem_payout": "0.003 STEEM",
"vesting_payout": "30.480632 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2018-06-12T09:08:06",
"trx_id": "0000000000000000000000000000000000000000",
"trx_in_block": 4294967295,
"virtual_op": 13
}2018/06/06 15:21:30
2018/06/06 15:21:30
| author | eversloth |
| body | 스팀잇이 많이 불친절하죠 ㅠㅠ 즐거운 스팀잇 활동 되시길! |
| json metadata | {"tags":["angular"],"app":"steemit/0.1"} |
| parent author | mnkim |
| parent permlink | re-eversloth-re-mnkim-angular-route-20180606t135708515z |
| permlink | re-mnkim-re-eversloth-re-mnkim-angular-route-20180606t152129093z |
| title | |
| Transaction Info | Block #23088221/Trx 97cd34b6fcbb473f4a63f94587726cd13860aaad |
View Raw JSON Data
{
"block": 23088221,
"op": [
"comment",
{
"author": "eversloth",
"body": "스팀잇이 많이 불친절하죠 ㅠㅠ 즐거운 스팀잇 활동 되시길!",
"json_metadata": "{\"tags\":[\"angular\"],\"app\":\"steemit/0.1\"}",
"parent_author": "mnkim",
"parent_permlink": "re-eversloth-re-mnkim-angular-route-20180606t135708515z",
"permlink": "re-mnkim-re-eversloth-re-mnkim-angular-route-20180606t152129093z",
"title": ""
}
],
"op_in_trx": 0,
"timestamp": "2018-06-06T15:21:30",
"trx_id": "97cd34b6fcbb473f4a63f94587726cd13860aaad",
"trx_in_block": 20,
"virtual_op": 0
}mnkimpublished a new post: angular-route2018/06/06 13:57:39
mnkimpublished a new post: angular-route
2018/06/06 13:57:39
| author | mnkim |
| body |  [블로터닷넷 기사](https://www.bloter.net/archives/281976)에 따르면 2017년 대한민국 1분기 평균 모바일 인터넷 속도는 28Mbps입니다. 이 속도로 계산된 [email protected]의 다운로드 시간은 8.5ms(아래 계산식 참고)입니다. 여기에 [LTE망 평균 응답속도 30ms](https://www.sktinsight.com/13617), 다운받은 스크립트를 [파싱하고 실행하는 데 까지 15ms(iPhone 5S 기준)](https://timkadlec.com/2014/09/js-parse-and-execution-time/)를 더하면 대략 53.5ms입니다. 시간이 지난 자료를 토대로 계산한 결과이지만. 이마저도 평균이거나 좋은 조건일때 기준이고. 보통 이런 파일을 하나만 다운로드하는것이 아니기 때문에 실제 서비스를 사용할 때는 더 느릴 것입니다. ``` 30KB after gzipped. 28Mbps = 3500KBps 1s : 3500KB = x : 30KB x = 0.008571429 ``` <br /> 서비스 초기 진입 시간의 중요성은 규모가 커질수록 중요해집니다. Google은 10개의 검색결과를 400ms에 노출하던 것에서. 30개의 검색결과를 900ms에 노출하도록 변경한 후 20%의 트래픽과 광고 수익 감소를 겪었다고 합니다. Google Maps는 리소스 용량을 30KB 줄인 것으로 첫주 10%의 트래픽 증가를. 이후 3주 내에 추가로 25%의 트래픽이 증가했다고 합니다. Amazon.com은 로드 타임이 100ms증가할때마다 매출액이 1%씩 감소했다고 합니다. [본문 링크](http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/) 위의 내용을 볼 때 30ms도 결코 작다고 할 수 없습니다. 서비스 초기 진입 시간을 줄일 수 있는 방법은 많지만 이 글에서 소개할 동적 모듈 로딩은 가장 간편하면서도 큰 효과를 볼 수 있는 기법입니다. Angular는 출시될때부터 이 기능을 가지고 있었습니다. 동적으로 받을 리소스들을 모아 별도의 모듈로 만들고 아래 코드와 같이 라우터에 등록하면 됩니다. ``` const routes: Routes = [{ path: 'customers', loadChildren: 'app/customers/customers.module#CustomersModule' }]; ``` <br /> 사용자가 `/customers`에 접속하면 자동으로 `app-customers-customers.module.js`파일을 동적으로 다운로드받고 파일 내 `CustomerModule`을 사용할 수 있게 됩니다. jQuery등의 라이브러리를 해당 페이지에서만 사용하는 것이 확실하다면. 이 분리된 모듈에서 사용하는것으로 간단히 기법을 적용할 수 있습니다. 이렇게 분리된 모듈 파일의 용량 만큼 서비스 초기 진입에 걸리는 시간을 줄일 수 있습니다. 하지만 어떤 모듈은 해당 컴포넌트가 사용되는 시점에 받는 것이 더 자연스럽고 편리한 경우가 있습니다. 위지윅 에디터를 예로 들 수 있습니다. 동적 모듈 로딩 없이 개발된 A페이지에 위지윅 에디터를 추가한다고 가정해 봅시다. 라우터에 기존에 등록된 컴포넌트를 모듈로 변경하고 위와 같이 수정해야 합니다. 또 이렇게 모듈을 동적으로 받는다고 해도. 만약 위지윅 에디터 자체를 특정 버튼으로 노출하도록 기획한 경우 실제 위지윅 에디터를 사용하지 않아도 페이지 진입 만으로 리소스를 받게 됩니다. 위지윅 에디터 컴포넌트를 실제로 사용하는 시점에 관련 모듈을 다운로드받도록 하고 싶으면 `NgModuleFactoryLoader`를 사용하면 됩니다. 이 모듈을 사용하기 위해서는 먼저 루트 모듈에 해당 모듈들을 추가해야 합니다. ``` @NgModule({ ... providers: [{provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader}] }) export class AppModule {} ``` <br /> 그리고 필요한 리소스들을 동적으로 로드하는 별도의 모듈을 만듭니다. ``` @NgModule() export class EditorModule { constructor(@Inject(DOCUMENT) private document: Document) {} async load() { const style = document.createElement('style'); style.textContent = require('../../assets/css/editor.css').default; this.document.head.appendChild(style); return require('../../assets/js/editor.js'); } } ``` 동적으로 다운로드할 모듈을 직접 사용하지 않아도 될 경우 코드를 생성자에 구현하면 됩니다. 예제 코드에서는 `editor.js`파일이 내보내는 함수를 직접 사용해야 하기 때문에 해당 모듈을 반환하는 별도의 메서드 `load`에 구현합니다. 모듈을 구현했으면 `angular.json` 파일에 해당 모듈을 등록합니다. ``` { "projects": { "my-app": { "architect": { "build": { "lazyModules": [ "src/app/modules/editor.module#EditorModule" ] } } } } } ``` <br /> `lazyModules`의 배열에 해당 모듈 파일의 경로와 모듈의 이름을 #으로 구분해 기재합니다. 이후 이 프로젝트가 빌드될 때 `editor.module.ts`, `editor.css`, `editor.js`파일들은 `src-app-modules-editor.module.js`로 묶여 별도의 파일로 분리됩니다. 이제 아래의 코드로 위지윅 에디터의 생성자를 동적으로 얻어올 수 있습니다. ``` @Component({...}) export class AppComponent { title = 'app'; @ViewChild('textarea') el: ElementRef; constructor(private injector: Injector, private loader: NgModuleFactoryLoader) {} onClickLoadEditor() { this.loader.load('src/app/modules/editor.module#EditorModule') .then(factory => factory.create(this.injector).instance.load()) .then(({Editor}) => new Editor(this.el.nativeElement)); } } ``` <br /> 사실 Angular@v5 이하에서는 webpack이 기본적으로 사용했던 `System.import`파서 플러그인으로 `.ts`파일 뿐만 아닌 여러 파일을 동적으로 간단히 분리할 수 있었습니다. 하지만 [email protected] 부터 webpack이 `System.import`파서 플러그인을 사용하지 않게 되었고. Angular@v6 버전 이후부터는 해당 코드가 발견되면 컴파일 시점에 경고를 출력합니다. 그렇기 때문에 `System.import`를 직접적으로 사용할 수 없고 본문과 같이 `NgModuleFactoryLoader`를 사용해야 합니다. 재미있는 것은 `NgModuleFactoryLoader`의 구현체인 `SystemJsNgModuleLoader`내부에서는 `System.import`를 아직 사용하고 있다는 것입니다. 공식 github에서는 이 코드를 typescript의 `import`문을 사용하는 것으로 수정하려는 [PR](https://github.com/angular/angular/issues/21560)이 있습니다. 이 PR이 머지된다고 하더라도. 위 방법을 이용하는 데 문제는 없습니다. |
| json metadata | {"tags":["angular","angular2","lazyloading","kr-newbie"],"image":["https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg"],"links":["https://www.bloter.net/archives/281976","https://www.sktinsight.com/13617","https://timkadlec.com/2014/09/js-parse-and-execution-time/","http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/","https://github.com/angular/angular/issues/21560"],"app":"steemit/0.1","format":"markdown"} |
| parent author | |
| parent permlink | angular |
| permlink | angular-route |
| title | Angular에서 Route없이 모듈 동적 로딩하기 |
| Transaction Info | Block #23086545/Trx dc39c22ca37f5e36b634e2cfe4f4207af71f78a4 |
View Raw JSON Data
{
"block": 23086545,
"op": [
"comment",
{
"author": "mnkim",
"body": "\n\n[블로터닷넷 기사](https://www.bloter.net/archives/281976)에 따르면 2017년 대한민국 1분기 평균 모바일 인터넷 속도는 28Mbps입니다. 이 속도로 계산된 [email protected]의 다운로드 시간은 8.5ms(아래 계산식 참고)입니다. 여기에 [LTE망 평균 응답속도 30ms](https://www.sktinsight.com/13617), 다운받은 스크립트를 [파싱하고 실행하는 데 까지 15ms(iPhone 5S 기준)](https://timkadlec.com/2014/09/js-parse-and-execution-time/)를 더하면 대략 53.5ms입니다. 시간이 지난 자료를 토대로 계산한 결과이지만. 이마저도 평균이거나 좋은 조건일때 기준이고. 보통 이런 파일을 하나만 다운로드하는것이 아니기 때문에 실제 서비스를 사용할 때는 더 느릴 것입니다.\n\n```\n30KB after gzipped.\n28Mbps = 3500KBps\n1s : 3500KB = x : 30KB\nx = 0.008571429\n```\n<br />\n서비스 초기 진입 시간의 중요성은 규모가 커질수록 중요해집니다. Google은 10개의 검색결과를 400ms에 노출하던 것에서. 30개의 검색결과를 900ms에 노출하도록 변경한 후 20%의 트래픽과 광고 수익 감소를 겪었다고 합니다. Google Maps는 리소스 용량을 30KB 줄인 것으로 첫주 10%의 트래픽 증가를. 이후 3주 내에 추가로 25%의 트래픽이 증가했다고 합니다. Amazon.com은 로드 타임이 100ms증가할때마다 매출액이 1%씩 감소했다고 합니다. [본문 링크](http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/)\n\n위의 내용을 볼 때 30ms도 결코 작다고 할 수 없습니다. 서비스 초기 진입 시간을 줄일 수 있는 방법은 많지만 이 글에서 소개할 동적 모듈 로딩은 가장 간편하면서도 큰 효과를 볼 수 있는 기법입니다. Angular는 출시될때부터 이 기능을 가지고 있었습니다. 동적으로 받을 리소스들을 모아 별도의 모듈로 만들고 아래 코드와 같이 라우터에 등록하면 됩니다.\n\n```\nconst routes: Routes = [{\n path: 'customers',\n loadChildren: 'app/customers/customers.module#CustomersModule'\n}];\n```\n<br />\n사용자가 `/customers`에 접속하면 자동으로 `app-customers-customers.module.js`파일을 동적으로 다운로드받고 파일 내 `CustomerModule`을 사용할 수 있게 됩니다. jQuery등의 라이브러리를 해당 페이지에서만 사용하는 것이 확실하다면. 이 분리된 모듈에서 사용하는것으로 간단히 기법을 적용할 수 있습니다. 이렇게 분리된 모듈 파일의 용량 만큼 서비스 초기 진입에 걸리는 시간을 줄일 수 있습니다.\n\n하지만 어떤 모듈은 해당 컴포넌트가 사용되는 시점에 받는 것이 더 자연스럽고 편리한 경우가 있습니다. 위지윅 에디터를 예로 들 수 있습니다. 동적 모듈 로딩 없이 개발된 A페이지에 위지윅 에디터를 추가한다고 가정해 봅시다. 라우터에 기존에 등록된 컴포넌트를 모듈로 변경하고 위와 같이 수정해야 합니다. 또 이렇게 모듈을 동적으로 받는다고 해도. 만약 위지윅 에디터 자체를 특정 버튼으로 노출하도록 기획한 경우 실제 위지윅 에디터를 사용하지 않아도 페이지 진입 만으로 리소스를 받게 됩니다.\n\n위지윅 에디터 컴포넌트를 실제로 사용하는 시점에 관련 모듈을 다운로드받도록 하고 싶으면 `NgModuleFactoryLoader`를 사용하면 됩니다. 이 모듈을 사용하기 위해서는 먼저 루트 모듈에 해당 모듈들을 추가해야 합니다.\n\n```\n@NgModule({\n ...\n providers: [{provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader}]\n})\nexport class AppModule {}\n```\n<br />\n그리고 필요한 리소스들을 동적으로 로드하는 별도의 모듈을 만듭니다.\n\n```\n@NgModule()\nexport class EditorModule {\n constructor(@Inject(DOCUMENT) private document: Document) {}\n\n async load() {\n const style = document.createElement('style');\n style.textContent = require('../../assets/css/editor.css').default;\n this.document.head.appendChild(style);\n\n return require('../../assets/js/editor.js');\n }\n}\n```\n\n동적으로 다운로드할 모듈을 직접 사용하지 않아도 될 경우 코드를 생성자에 구현하면 됩니다. 예제 코드에서는 `editor.js`파일이 내보내는 함수를 직접 사용해야 하기 때문에 해당 모듈을 반환하는 별도의 메서드 `load`에 구현합니다. 모듈을 구현했으면 `angular.json` 파일에 해당 모듈을 등록합니다.\n\n```\n{\n \"projects\": {\n \"my-app\": {\n \"architect\": {\n \"build\": {\n \"lazyModules\": [\n \"src/app/modules/editor.module#EditorModule\"\n ]\n }\n }\n }\n }\n}\n```\n<br />\n`lazyModules`의 배열에 해당 모듈 파일의 경로와 모듈의 이름을 #으로 구분해 기재합니다. 이후 이 프로젝트가 빌드될 때 `editor.module.ts`, `editor.css`, `editor.js`파일들은 `src-app-modules-editor.module.js`로 묶여 별도의 파일로 분리됩니다. 이제 아래의 코드로 위지윅 에디터의 생성자를 동적으로 얻어올 수 있습니다.\n\n```\n@Component({...})\nexport class AppComponent {\n title = 'app';\n @ViewChild('textarea') el: ElementRef;\n\n constructor(private injector: Injector, private loader: NgModuleFactoryLoader) {}\n\n onClickLoadEditor() {\n this.loader.load('src/app/modules/editor.module#EditorModule')\n .then(factory => factory.create(this.injector).instance.load())\n .then(({Editor}) => new Editor(this.el.nativeElement));\n }\n}\n```\n<br />\n사실 Angular@v5 이하에서는 webpack이 기본적으로 사용했던 `System.import`파서 플러그인으로 `.ts`파일 뿐만 아닌 여러 파일을 동적으로 간단히 분리할 수 있었습니다. 하지만 [email protected] 부터 webpack이 `System.import`파서 플러그인을 사용하지 않게 되었고. Angular@v6 버전 이후부터는 해당 코드가 발견되면 컴파일 시점에 경고를 출력합니다. 그렇기 때문에 `System.import`를 직접적으로 사용할 수 없고 본문과 같이 `NgModuleFactoryLoader`를 사용해야 합니다.\n\n재미있는 것은 `NgModuleFactoryLoader`의 구현체인 `SystemJsNgModuleLoader`내부에서는 `System.import`를 아직 사용하고 있다는 것입니다. 공식 github에서는 이 코드를 typescript의 `import`문을 사용하는 것으로 수정하려는 [PR](https://github.com/angular/angular/issues/21560)이 있습니다. 이 PR이 머지된다고 하더라도. 위 방법을 이용하는 데 문제는 없습니다.",
"json_metadata": "{\"tags\":[\"angular\",\"angular2\",\"lazyloading\",\"kr-newbie\"],\"image\":[\"https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg\"],\"links\":[\"https://www.bloter.net/archives/281976\",\"https://www.sktinsight.com/13617\",\"https://timkadlec.com/2014/09/js-parse-and-execution-time/\",\"http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/\",\"https://github.com/angular/angular/issues/21560\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular-route",
"title": "Angular에서 Route없이 모듈 동적 로딩하기"
}
],
"op_in_trx": 0,
"timestamp": "2018-06-06T13:57:39",
"trx_id": "dc39c22ca37f5e36b634e2cfe4f4207af71f78a4",
"trx_in_block": 58,
"virtual_op": 0
}mnkimupvoted (100.00%) @eversloth / re-mnkim-angular-route-20180606t134426151z2018/06/06 13:57:15
mnkimupvoted (100.00%) @eversloth / re-mnkim-angular-route-20180606t134426151z
2018/06/06 13:57:15
| author | eversloth |
| permlink | re-mnkim-angular-route-20180606t134426151z |
| voter | mnkim |
| weight | 10000 (100.00%) |
| Transaction Info | Block #23086537/Trx 15555b2b62e6cf203186e7b2967fecb7fc8d5dd5 |
View Raw JSON Data
{
"block": 23086537,
"op": [
"vote",
{
"author": "eversloth",
"permlink": "re-mnkim-angular-route-20180606t134426151z",
"voter": "mnkim",
"weight": 10000
}
],
"op_in_trx": 0,
"timestamp": "2018-06-06T13:57:15",
"trx_id": "15555b2b62e6cf203186e7b2967fecb7fc8d5dd5",
"trx_in_block": 58,
"virtual_op": 0
}2018/06/06 13:57:09
2018/06/06 13:57:09
| author | mnkim |
| body | 와 좋은 팁 고맙습니다. 사실 맨땅에 헤딩하는 기분으로 글을 쓰고 태그를 달고있긴한데 이런 방법이 있었군요! 알려주신 링크도 정독하겠습니다. 고마워요! |
| json metadata | {"tags":["angular"],"app":"steemit/0.1"} |
| parent author | eversloth |
| parent permlink | re-mnkim-angular-route-20180606t134426151z |
| permlink | re-eversloth-re-mnkim-angular-route-20180606t135708515z |
| title | |
| Transaction Info | Block #23086535/Trx 809b3c9257b1515fb606731649831227de0352f7 |
View Raw JSON Data
{
"block": 23086535,
"op": [
"comment",
{
"author": "mnkim",
"body": "와 좋은 팁 고맙습니다. 사실 맨땅에 헤딩하는 기분으로 글을 쓰고 태그를 달고있긴한데 이런 방법이 있었군요! 알려주신 링크도 정독하겠습니다. 고마워요!",
"json_metadata": "{\"tags\":[\"angular\"],\"app\":\"steemit/0.1\"}",
"parent_author": "eversloth",
"parent_permlink": "re-mnkim-angular-route-20180606t134426151z",
"permlink": "re-eversloth-re-mnkim-angular-route-20180606t135708515z",
"title": ""
}
],
"op_in_trx": 0,
"timestamp": "2018-06-06T13:57:09",
"trx_id": "809b3c9257b1515fb606731649831227de0352f7",
"trx_in_block": 42,
"virtual_op": 0
}everslothupvoted (20.00%) @mnkim / angular-route2018/06/06 13:44:42
everslothupvoted (20.00%) @mnkim / angular-route
2018/06/06 13:44:42
| author | mnkim |
| permlink | angular-route |
| voter | eversloth |
| weight | 2000 (20.00%) |
| Transaction Info | Block #23086286/Trx c04f58eff3b60ce95b8b57e445bb67984eb36217 |
View Raw JSON Data
{
"block": 23086286,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular-route",
"voter": "eversloth",
"weight": 2000
}
],
"op_in_trx": 0,
"timestamp": "2018-06-06T13:44:42",
"trx_id": "c04f58eff3b60ce95b8b57e445bb67984eb36217",
"trx_in_block": 51,
"virtual_op": 0
}2018/06/06 13:44:27
2018/06/06 13:44:27
| author | eversloth |
| body | LTE가 꽤나 빠르다고는 해도 반응시간이 무시 못할 수준이군요.. 좋은 정보 감사합니다. #kr 태그를 달지 않으시면 한국어 사용자에게 글이 잘 노출되지 않습니다. 스팀잇에 익숙해지실 때까지 #kr-newbie 태그를 사용하시는 것을 추천드립니다. #kr 커뮤니티에서 사용하는 태그 목록은 [@myfan 님의 태그 정리글](https://steemit.com/kr/@myfan/5-7)에서 확인하실 수 있습니다. [이지스팀잇 가이드북](https://steemit.com/kr/@easysteemit/3s7jfa-pdf) 을 보시면 앞으로 스팀잇 활동하시는데 도움이 되실겁니다. |
| json metadata | {"tags":["angular","kr","kr-newbie"],"links":["https://steemit.com/kr/@myfan/5-7","https://steemit.com/kr/@easysteemit/3s7jfa-pdf"],"app":"steemit/0.1"} |
| parent author | mnkim |
| parent permlink | angular-route |
| permlink | re-mnkim-angular-route-20180606t134426151z |
| title | |
| Transaction Info | Block #23086281/Trx 3f2cf21dec9b2a0d1c50fc9d3835d2bf9b067392 |
View Raw JSON Data
{
"block": 23086281,
"op": [
"comment",
{
"author": "eversloth",
"body": "LTE가 꽤나 빠르다고는 해도 반응시간이 무시 못할 수준이군요.. 좋은 정보 감사합니다.\n\n#kr 태그를 달지 않으시면 한국어 사용자에게 글이 잘 노출되지 않습니다. 스팀잇에 익숙해지실 때까지 #kr-newbie 태그를 사용하시는 것을 추천드립니다. #kr 커뮤니티에서 사용하는 태그 목록은 [@myfan 님의 태그 정리글](https://steemit.com/kr/@myfan/5-7)에서 확인하실 수 있습니다.\n[이지스팀잇 가이드북](https://steemit.com/kr/@easysteemit/3s7jfa-pdf) 을 보시면 앞으로 스팀잇 활동하시는데 도움이 되실겁니다.",
"json_metadata": "{\"tags\":[\"angular\",\"kr\",\"kr-newbie\"],\"links\":[\"https://steemit.com/kr/@myfan/5-7\",\"https://steemit.com/kr/@easysteemit/3s7jfa-pdf\"],\"app\":\"steemit/0.1\"}",
"parent_author": "mnkim",
"parent_permlink": "angular-route",
"permlink": "re-mnkim-angular-route-20180606t134426151z",
"title": ""
}
],
"op_in_trx": 0,
"timestamp": "2018-06-06T13:44:27",
"trx_id": "3f2cf21dec9b2a0d1c50fc9d3835d2bf9b067392",
"trx_in_block": 22,
"virtual_op": 0
}mnkimpublished a new post: angular-route2018/06/05 14:33:03
mnkimpublished a new post: angular-route
2018/06/05 14:33:03
| author | mnkim |
| body | @@ -3025,17 +3025,20 @@ itor.js%60 -%EA%B0%80 +%ED%8C%8C%EC%9D%BC%EB%93%A4%EC%9D%80 %60src-ap @@ -3070,12 +3070,10 @@ s%60%EB%A1%9C -%EB%B6%84%EB%A6%AC%EB%90%98%EC%96%B4 +%EB%AC%B6%EC%97%AC %EB%B3%84%EB%8F%84%EC%9D%98 @@ -3077,18 +3077,18 @@ %EB%B3%84%EB%8F%84%EC%9D%98 %ED%8C%8C%EC%9D%BC%EB%A1%9C -%EC%83%9D%EC%84%B1 +%EB%B6%84%EB%A6%AC %EB%90%A9%EB%8B%88%EB%8B%A4. %EC%9D%B4%EC%A0%9C |
| json metadata | {"tags":["angular","angular2","lazyloading"],"image":["https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg"],"links":["https://www.bloter.net/archives/281976","https://www.sktinsight.com/13617","https://timkadlec.com/2014/09/js-parse-and-execution-time/","http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/","https://github.com/angular/angular/issues/21560"],"app":"steemit/0.1","format":"markdown"} |
| parent author | |
| parent permlink | angular |
| permlink | angular-route |
| title | Angular에서 Route없이 모듈 동적 로딩하기 |
| Transaction Info | Block #23058462/Trx d329f686cafa5ccff8eb9698e3c68f02638c9b21 |
View Raw JSON Data
{
"block": 23058462,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -3025,17 +3025,20 @@\n itor.js%60\n-%EA%B0%80\n+%ED%8C%8C%EC%9D%BC%EB%93%A4%EC%9D%80\n %60src-ap\n@@ -3070,12 +3070,10 @@\n s%60%EB%A1%9C \n-%EB%B6%84%EB%A6%AC%EB%90%98%EC%96%B4\n+%EB%AC%B6%EC%97%AC\n %EB%B3%84%EB%8F%84%EC%9D%98\n@@ -3077,18 +3077,18 @@\n %EB%B3%84%EB%8F%84%EC%9D%98 %ED%8C%8C%EC%9D%BC%EB%A1%9C \n-%EC%83%9D%EC%84%B1\n+%EB%B6%84%EB%A6%AC\n %EB%90%A9%EB%8B%88%EB%8B%A4. %EC%9D%B4%EC%A0%9C \n",
"json_metadata": "{\"tags\":[\"angular\",\"angular2\",\"lazyloading\"],\"image\":[\"https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg\"],\"links\":[\"https://www.bloter.net/archives/281976\",\"https://www.sktinsight.com/13617\",\"https://timkadlec.com/2014/09/js-parse-and-execution-time/\",\"http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/\",\"https://github.com/angular/angular/issues/21560\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular-route",
"title": "Angular에서 Route없이 모듈 동적 로딩하기"
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T14:33:03",
"trx_id": "d329f686cafa5ccff8eb9698e3c68f02638c9b21",
"trx_in_block": 4,
"virtual_op": 0
}swaggerupvoted (0.03%) @mnkim / angular-route2018/06/05 14:32:42
swaggerupvoted (0.03%) @mnkim / angular-route
2018/06/05 14:32:42
| author | mnkim |
| permlink | angular-route |
| voter | swagger |
| weight | 3 (0.03%) |
| Transaction Info | Block #23058455/Trx 5cc480e0a42289798727453e3da82a3e3d225f9d |
View Raw JSON Data
{
"block": 23058455,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular-route",
"voter": "swagger",
"weight": 3
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T14:32:42",
"trx_id": "5cc480e0a42289798727453e3da82a3e3d225f9d",
"trx_in_block": 0,
"virtual_op": 0
}mnkimpublished a new post: angular-route2018/06/05 14:31:12
mnkimpublished a new post: angular-route
2018/06/05 14:31:12
| author | mnkim |
| body | @@ -106,16 +106,58 @@ g)%0A%0A +%5B %EB%B8%94%EB%A1%9C%ED%84%B0%EB%8B%B7%EB%84%B7 %EA%B8%B0%EC%82%AC +%5D(https://www.bloter.net/archives/281976) %EC%97%90 %EB%94%B0%EB%A5%B4 @@ -257,16 +257,17 @@ %EB%8B%88%EB%8B%A4. %EC%97%AC%EA%B8%B0%EC%97%90 +%5B LTE%EB%A7%9D %ED%8F%89%EA%B7%A0 @@ -275,16 +275,51 @@ %EB%8B%B5%EC%86%8D%EB%8F%84 30ms +%5D(https://www.sktinsight.com/13617) , %EB%8B%A4%EC%9A%B4%EB%B0%9B%EC%9D%80 %EC%8A%A4 @@ -323,16 +323,17 @@ %EC%9D%80 %EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC +%5B %ED%8C%8C%EC%8B%B1%ED%95%98%EA%B3%A0 %EC%8B%A4%ED%96%89%ED%95%98 @@ -357,16 +357,77 @@ e 5S %EA%B8%B0%EC%A4%80) +%5D(https://timkadlec.com/2014/09/js-parse-and-execution-time/) %EB%A5%BC %EB%8D%94%ED%95%98%EB%A9%B4 %EB%8C%80%EB%9E%B5 @@ -906,16 +906,25 @@ %EB%8B%A4%EA%B3%A0 %ED%95%A9%EB%8B%88%EB%8B%A4. + %5B%EB%B3%B8%EB%AC%B8 %EB%A7%81%ED%81%AC%5D( http://w @@ -989,16 +989,17 @@ ormance/ +) %0A%0A%EC%9C%84%EC%9D%98 %EB%82%B4%EC%9A%A9%EC%9D%84 |
| json metadata | {"tags":["angular","angular2","lazyloading"],"image":["https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg"],"links":["https://www.bloter.net/archives/281976","https://www.sktinsight.com/13617","https://timkadlec.com/2014/09/js-parse-and-execution-time/","http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/","https://github.com/angular/angular/issues/21560"],"app":"steemit/0.1","format":"markdown"} |
| parent author | |
| parent permlink | angular |
| permlink | angular-route |
| title | Angular에서 Route없이 모듈 동적 로딩하기 |
| Transaction Info | Block #23058425/Trx ff7dab786866148b5933f89967433d0ba424f352 |
View Raw JSON Data
{
"block": 23058425,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -106,16 +106,58 @@\n g)%0A%0A\n+%5B\n %EB%B8%94%EB%A1%9C%ED%84%B0%EB%8B%B7%EB%84%B7 %EA%B8%B0%EC%82%AC\n+%5D(https://www.bloter.net/archives/281976)\n %EC%97%90 %EB%94%B0%EB%A5%B4\n@@ -257,16 +257,17 @@\n %EB%8B%88%EB%8B%A4. %EC%97%AC%EA%B8%B0%EC%97%90 \n+%5B\n LTE%EB%A7%9D %ED%8F%89%EA%B7%A0 \n@@ -275,16 +275,51 @@\n %EB%8B%B5%EC%86%8D%EB%8F%84 30ms\n+%5D(https://www.sktinsight.com/13617)\n , %EB%8B%A4%EC%9A%B4%EB%B0%9B%EC%9D%80 %EC%8A%A4\n@@ -323,16 +323,17 @@\n %EC%9D%80 %EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC \n+%5B\n %ED%8C%8C%EC%8B%B1%ED%95%98%EA%B3%A0 %EC%8B%A4%ED%96%89%ED%95%98\n@@ -357,16 +357,77 @@\n e 5S %EA%B8%B0%EC%A4%80)\n+%5D(https://timkadlec.com/2014/09/js-parse-and-execution-time/)\n %EB%A5%BC %EB%8D%94%ED%95%98%EB%A9%B4 %EB%8C%80%EB%9E%B5\n@@ -906,16 +906,25 @@\n %EB%8B%A4%EA%B3%A0 %ED%95%A9%EB%8B%88%EB%8B%A4. \n+ %5B%EB%B3%B8%EB%AC%B8 %EB%A7%81%ED%81%AC%5D(\n http://w\n@@ -989,16 +989,17 @@\n ormance/\n+)\n %0A%0A%EC%9C%84%EC%9D%98 %EB%82%B4%EC%9A%A9%EC%9D%84\n",
"json_metadata": "{\"tags\":[\"angular\",\"angular2\",\"lazyloading\"],\"image\":[\"https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg\"],\"links\":[\"https://www.bloter.net/archives/281976\",\"https://www.sktinsight.com/13617\",\"https://timkadlec.com/2014/09/js-parse-and-execution-time/\",\"http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/\",\"https://github.com/angular/angular/issues/21560\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular-route",
"title": "Angular에서 Route없이 모듈 동적 로딩하기"
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T14:31:12",
"trx_id": "ff7dab786866148b5933f89967433d0ba424f352",
"trx_in_block": 9,
"virtual_op": 0
}dongkunupvoted (100.00%) @mnkim / angular-route2018/06/05 13:09:48
dongkunupvoted (100.00%) @mnkim / angular-route
2018/06/05 13:09:48
| author | mnkim |
| permlink | angular-route |
| voter | dongkun |
| weight | 10000 (100.00%) |
| Transaction Info | Block #23056797/Trx 45cda5d522627f1754fcb367ece2de45e59d2e0f |
View Raw JSON Data
{
"block": 23056797,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular-route",
"voter": "dongkun",
"weight": 10000
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T13:09:48",
"trx_id": "45cda5d522627f1754fcb367ece2de45e59d2e0f",
"trx_in_block": 32,
"virtual_op": 0
}mnkimpublished a new post: angular-route2018/06/05 09:20:39
mnkimpublished a new post: angular-route
2018/06/05 09:20:39
| author | mnkim |
| body | @@ -3882,18 +3882,69 @@ %EB%A1%9C %EC%88%98%EC%A0%95%ED%95%98%EB%A0%A4%EB%8A%94 +%5B PR +%5D(https://github.com/angular/angular/issues/21560) %EC%9D%B4 %EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4. |
| json metadata | {"tags":["angular","angular2","lazyloading"],"image":["https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg"],"links":["http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/","https://github.com/angular/angular/issues/21560"],"app":"steemit/0.1","format":"markdown"} |
| parent author | |
| parent permlink | angular |
| permlink | angular-route |
| title | Angular에서 Route없이 모듈 동적 로딩하기 |
| Transaction Info | Block #23052215/Trx 7512e7c9be6a66a32a3c7830585c027dbc609fa1 |
View Raw JSON Data
{
"block": 23052215,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -3882,18 +3882,69 @@\n %EB%A1%9C %EC%88%98%EC%A0%95%ED%95%98%EB%A0%A4%EB%8A%94 \n+%5B\n PR\n+%5D(https://github.com/angular/angular/issues/21560)\n %EC%9D%B4 %EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4. \n",
"json_metadata": "{\"tags\":[\"angular\",\"angular2\",\"lazyloading\"],\"image\":[\"https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg\"],\"links\":[\"http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/\",\"https://github.com/angular/angular/issues/21560\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular-route",
"title": "Angular에서 Route없이 모듈 동적 로딩하기"
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T09:20:39",
"trx_id": "7512e7c9be6a66a32a3c7830585c027dbc609fa1",
"trx_in_block": 69,
"virtual_op": 0
}mnkimpublished a new post: angular-route2018/06/05 09:19:30
mnkimpublished a new post: angular-route
2018/06/05 09:19:30
| author | mnkim |
| body | @@ -492,17 +492,23 @@ 429%0A%60%60%60%0A +%3Cbr /%3E %0A - %EC%84%9C%EB%B9%84%EC%8A%A4 %EC%B4%88%EA%B8%B0 %EC%A7%84 @@ -1169,17 +1169,23 @@ %7D%5D;%0A%60%60%60%0A +%3Cbr /%3E %0A - %EC%82%AC%EC%9A%A9%EC%9E%90%EA%B0%80 %60/c @@ -1966,17 +1966,23 @@ %7B%7D%0A%60%60%60%0A +%3Cbr /%3E %0A - %EA%B7%B8%EB%A6%AC%EA%B3%A0 %ED%95%84%EC%9A%94%ED%95%9C @@ -2750,17 +2750,23 @@ %7D%0A%7D%0A%60%60%60%0A +%3Cbr /%3E %0A - %60lazyMod @@ -3407,16 +3407,22 @@ %7D%0A%7D%0A%60%60%60%0A +%3Cbr /%3E %0A%EC%82%AC%EC%8B%A4 Angu |
| json metadata | {"tags":["angular","angular2","lazyloading"],"image":["https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg"],"links":["http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/"],"app":"steemit/0.1","format":"markdown"} |
| parent author | |
| parent permlink | angular |
| permlink | angular-route |
| title | Angular에서 Route없이 모듈 동적 로딩하기 |
| Transaction Info | Block #23052192/Trx 512ea1fe0901b2c088b1682502686a60c845b4a8 |
View Raw JSON Data
{
"block": 23052192,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -492,17 +492,23 @@\n 429%0A%60%60%60%0A\n+%3Cbr /%3E\n %0A\n-\n %EC%84%9C%EB%B9%84%EC%8A%A4 %EC%B4%88%EA%B8%B0 %EC%A7%84\n@@ -1169,17 +1169,23 @@\n %7D%5D;%0A%60%60%60%0A\n+%3Cbr /%3E\n %0A\n-\n %EC%82%AC%EC%9A%A9%EC%9E%90%EA%B0%80 %60/c\n@@ -1966,17 +1966,23 @@\n %7B%7D%0A%60%60%60%0A\n+%3Cbr /%3E\n %0A\n-\n %EA%B7%B8%EB%A6%AC%EA%B3%A0 %ED%95%84%EC%9A%94%ED%95%9C \n@@ -2750,17 +2750,23 @@\n %7D%0A%7D%0A%60%60%60%0A\n+%3Cbr /%3E\n %0A\n-\n %60lazyMod\n@@ -3407,16 +3407,22 @@\n %7D%0A%7D%0A%60%60%60%0A\n+%3Cbr /%3E\n %0A%EC%82%AC%EC%8B%A4 Angu\n",
"json_metadata": "{\"tags\":[\"angular\",\"angular2\",\"lazyloading\"],\"image\":[\"https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg\"],\"links\":[\"http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular-route",
"title": "Angular에서 Route없이 모듈 동적 로딩하기"
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T09:19:30",
"trx_id": "512ea1fe0901b2c088b1682502686a60c845b4a8",
"trx_in_block": 14,
"virtual_op": 0
}aripratamaupvoted (100.00%) @mnkim / angular-route2018/06/05 09:08:42
aripratamaupvoted (100.00%) @mnkim / angular-route
2018/06/05 09:08:42
| author | mnkim |
| permlink | angular-route |
| voter | aripratama |
| weight | 10000 (100.00%) |
| Transaction Info | Block #23051976/Trx 53b606abf5d7a4187fb85af0642554bd4377d9b8 |
View Raw JSON Data
{
"block": 23051976,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular-route",
"voter": "aripratama",
"weight": 10000
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T09:08:42",
"trx_id": "53b606abf5d7a4187fb85af0642554bd4377d9b8",
"trx_in_block": 51,
"virtual_op": 0
}modemserupvoted (1.00%) @mnkim / angular-route2018/06/05 09:08:09
modemserupvoted (1.00%) @mnkim / angular-route
2018/06/05 09:08:09
| author | mnkim |
| permlink | angular-route |
| voter | modemser |
| weight | 100 (1.00%) |
| Transaction Info | Block #23051965/Trx 46d3d9350da3ced7122e3e9d2e5050c87ec7be7b |
View Raw JSON Data
{
"block": 23051965,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular-route",
"voter": "modemser",
"weight": 100
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T09:08:09",
"trx_id": "46d3d9350da3ced7122e3e9d2e5050c87ec7be7b",
"trx_in_block": 26,
"virtual_op": 0
}mnkimpublished a new post: angular-route2018/06/05 09:08:06
mnkimpublished a new post: angular-route
2018/06/05 09:08:06
| author | mnkim |
| body |  블로터닷넷 기사에 따르면 2017년 대한민국 1분기 평균 모바일 인터넷 속도는 28Mbps입니다. 이 속도로 계산된 [email protected]의 다운로드 시간은 8.5ms(아래 계산식 참고)입니다. 여기에 LTE망 평균 응답속도 30ms, 다운받은 스크립트를 파싱하고 실행하는 데 까지 15ms(iPhone 5S 기준)를 더하면 대략 53.5ms입니다. 시간이 지난 자료를 토대로 계산한 결과이지만. 이마저도 평균이거나 좋은 조건일때 기준이고. 보통 이런 파일을 하나만 다운로드하는것이 아니기 때문에 실제 서비스를 사용할 때는 더 느릴 것입니다. ``` 30KB after gzipped. 28Mbps = 3500KBps 1s : 3500KB = x : 30KB x = 0.008571429 ``` 서비스 초기 진입 시간의 중요성은 규모가 커질수록 중요해집니다. Google은 10개의 검색결과를 400ms에 노출하던 것에서. 30개의 검색결과를 900ms에 노출하도록 변경한 후 20%의 트래픽과 광고 수익 감소를 겪었다고 합니다. Google Maps는 리소스 용량을 30KB 줄인 것으로 첫주 10%의 트래픽 증가를. 이후 3주 내에 추가로 25%의 트래픽이 증가했다고 합니다. Amazon.com은 로드 타임이 100ms증가할때마다 매출액이 1%씩 감소했다고 합니다. http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/ 위의 내용을 볼 때 30ms도 결코 작다고 할 수 없습니다. 서비스 초기 진입 시간을 줄일 수 있는 방법은 많지만 이 글에서 소개할 동적 모듈 로딩은 가장 간편하면서도 큰 효과를 볼 수 있는 기법입니다. Angular는 출시될때부터 이 기능을 가지고 있었습니다. 동적으로 받을 리소스들을 모아 별도의 모듈로 만들고 아래 코드와 같이 라우터에 등록하면 됩니다. ``` const routes: Routes = [{ path: 'customers', loadChildren: 'app/customers/customers.module#CustomersModule' }]; ``` 사용자가 `/customers`에 접속하면 자동으로 `app-customers-customers.module.js`파일을 동적으로 다운로드받고 파일 내 `CustomerModule`을 사용할 수 있게 됩니다. jQuery등의 라이브러리를 해당 페이지에서만 사용하는 것이 확실하다면. 이 분리된 모듈에서 사용하는것으로 간단히 기법을 적용할 수 있습니다. 이렇게 분리된 모듈 파일의 용량 만큼 서비스 초기 진입에 걸리는 시간을 줄일 수 있습니다. 하지만 어떤 모듈은 해당 컴포넌트가 사용되는 시점에 받는 것이 더 자연스럽고 편리한 경우가 있습니다. 위지윅 에디터를 예로 들 수 있습니다. 동적 모듈 로딩 없이 개발된 A페이지에 위지윅 에디터를 추가한다고 가정해 봅시다. 라우터에 기존에 등록된 컴포넌트를 모듈로 변경하고 위와 같이 수정해야 합니다. 또 이렇게 모듈을 동적으로 받는다고 해도. 만약 위지윅 에디터 자체를 특정 버튼으로 노출하도록 기획한 경우 실제 위지윅 에디터를 사용하지 않아도 페이지 진입 만으로 리소스를 받게 됩니다. 위지윅 에디터 컴포넌트를 실제로 사용하는 시점에 관련 모듈을 다운로드받도록 하고 싶으면 `NgModuleFactoryLoader`를 사용하면 됩니다. 이 모듈을 사용하기 위해서는 먼저 루트 모듈에 해당 모듈들을 추가해야 합니다. ``` @NgModule({ ... providers: [{provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader}] }) export class AppModule {} ``` 그리고 필요한 리소스들을 동적으로 로드하는 별도의 모듈을 만듭니다. ``` @NgModule() export class EditorModule { constructor(@Inject(DOCUMENT) private document: Document) {} async load() { const style = document.createElement('style'); style.textContent = require('../../assets/css/editor.css').default; this.document.head.appendChild(style); return require('../../assets/js/editor.js'); } } ``` 동적으로 다운로드할 모듈을 직접 사용하지 않아도 될 경우 코드를 생성자에 구현하면 됩니다. 예제 코드에서는 `editor.js`파일이 내보내는 함수를 직접 사용해야 하기 때문에 해당 모듈을 반환하는 별도의 메서드 `load`에 구현합니다. 모듈을 구현했으면 `angular.json` 파일에 해당 모듈을 등록합니다. ``` { "projects": { "my-app": { "architect": { "build": { "lazyModules": [ "src/app/modules/editor.module#EditorModule" ] } } } } } ``` `lazyModules`의 배열에 해당 모듈 파일의 경로와 모듈의 이름을 #으로 구분해 기재합니다. 이후 이 프로젝트가 빌드될 때 `editor.module.ts`, `editor.css`, `editor.js`가 `src-app-modules-editor.module.js`로 분리되어 별도의 파일로 생성됩니다. 이제 아래의 코드로 위지윅 에디터의 생성자를 동적으로 얻어올 수 있습니다. ``` @Component({...}) export class AppComponent { title = 'app'; @ViewChild('textarea') el: ElementRef; constructor(private injector: Injector, private loader: NgModuleFactoryLoader) {} onClickLoadEditor() { this.loader.load('src/app/modules/editor.module#EditorModule') .then(factory => factory.create(this.injector).instance.load()) .then(({Editor}) => new Editor(this.el.nativeElement)); } } ``` 사실 Angular@v5 이하에서는 webpack이 기본적으로 사용했던 `System.import`파서 플러그인으로 `.ts`파일 뿐만 아닌 여러 파일을 동적으로 간단히 분리할 수 있었습니다. 하지만 [email protected] 부터 webpack이 `System.import`파서 플러그인을 사용하지 않게 되었고. Angular@v6 버전 이후부터는 해당 코드가 발견되면 컴파일 시점에 경고를 출력합니다. 그렇기 때문에 `System.import`를 직접적으로 사용할 수 없고 본문과 같이 `NgModuleFactoryLoader`를 사용해야 합니다. 재미있는 것은 `NgModuleFactoryLoader`의 구현체인 `SystemJsNgModuleLoader`내부에서는 `System.import`를 아직 사용하고 있다는 것입니다. 공식 github에서는 이 코드를 typescript의 `import`문을 사용하는 것으로 수정하려는 PR이 있습니다. 이 PR이 머지된다고 하더라도. 위 방법을 이용하는 데 문제는 없습니다. |
| json metadata | {"tags":["angular","angular2","lazyloading"],"image":["https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg"],"links":["http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/"],"app":"steemit/0.1","format":"markdown"} |
| parent author | |
| parent permlink | angular |
| permlink | angular-route |
| title | Angular에서 Route없이 모듈 동적 로딩하기 |
| Transaction Info | Block #23051964/Trx 2d82e847cdb4d8e844fcd4ca3b13b7076072ec99 |
View Raw JSON Data
{
"block": 23051964,
"op": [
"comment",
{
"author": "mnkim",
"body": "\n\n블로터닷넷 기사에 따르면 2017년 대한민국 1분기 평균 모바일 인터넷 속도는 28Mbps입니다. 이 속도로 계산된 [email protected]의 다운로드 시간은 8.5ms(아래 계산식 참고)입니다. 여기에 LTE망 평균 응답속도 30ms, 다운받은 스크립트를 파싱하고 실행하는 데 까지 15ms(iPhone 5S 기준)를 더하면 대략 53.5ms입니다. 시간이 지난 자료를 토대로 계산한 결과이지만. 이마저도 평균이거나 좋은 조건일때 기준이고. 보통 이런 파일을 하나만 다운로드하는것이 아니기 때문에 실제 서비스를 사용할 때는 더 느릴 것입니다.\n\n```\n30KB after gzipped.\n28Mbps = 3500KBps\n1s : 3500KB = x : 30KB\nx = 0.008571429\n```\n\n서비스 초기 진입 시간의 중요성은 규모가 커질수록 중요해집니다. Google은 10개의 검색결과를 400ms에 노출하던 것에서. 30개의 검색결과를 900ms에 노출하도록 변경한 후 20%의 트래픽과 광고 수익 감소를 겪었다고 합니다. Google Maps는 리소스 용량을 30KB 줄인 것으로 첫주 10%의 트래픽 증가를. 이후 3주 내에 추가로 25%의 트래픽이 증가했다고 합니다. Amazon.com은 로드 타임이 100ms증가할때마다 매출액이 1%씩 감소했다고 합니다. http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/\n\n위의 내용을 볼 때 30ms도 결코 작다고 할 수 없습니다. 서비스 초기 진입 시간을 줄일 수 있는 방법은 많지만 이 글에서 소개할 동적 모듈 로딩은 가장 간편하면서도 큰 효과를 볼 수 있는 기법입니다. Angular는 출시될때부터 이 기능을 가지고 있었습니다. 동적으로 받을 리소스들을 모아 별도의 모듈로 만들고 아래 코드와 같이 라우터에 등록하면 됩니다.\n\n```\nconst routes: Routes = [{\n path: 'customers',\n loadChildren: 'app/customers/customers.module#CustomersModule'\n}];\n```\n\n사용자가 `/customers`에 접속하면 자동으로 `app-customers-customers.module.js`파일을 동적으로 다운로드받고 파일 내 `CustomerModule`을 사용할 수 있게 됩니다. jQuery등의 라이브러리를 해당 페이지에서만 사용하는 것이 확실하다면. 이 분리된 모듈에서 사용하는것으로 간단히 기법을 적용할 수 있습니다. 이렇게 분리된 모듈 파일의 용량 만큼 서비스 초기 진입에 걸리는 시간을 줄일 수 있습니다.\n\n하지만 어떤 모듈은 해당 컴포넌트가 사용되는 시점에 받는 것이 더 자연스럽고 편리한 경우가 있습니다. 위지윅 에디터를 예로 들 수 있습니다. 동적 모듈 로딩 없이 개발된 A페이지에 위지윅 에디터를 추가한다고 가정해 봅시다. 라우터에 기존에 등록된 컴포넌트를 모듈로 변경하고 위와 같이 수정해야 합니다. 또 이렇게 모듈을 동적으로 받는다고 해도. 만약 위지윅 에디터 자체를 특정 버튼으로 노출하도록 기획한 경우 실제 위지윅 에디터를 사용하지 않아도 페이지 진입 만으로 리소스를 받게 됩니다.\n\n위지윅 에디터 컴포넌트를 실제로 사용하는 시점에 관련 모듈을 다운로드받도록 하고 싶으면 `NgModuleFactoryLoader`를 사용하면 됩니다. 이 모듈을 사용하기 위해서는 먼저 루트 모듈에 해당 모듈들을 추가해야 합니다.\n\n```\n@NgModule({\n ...\n providers: [{provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader}]\n})\nexport class AppModule {}\n```\n\n그리고 필요한 리소스들을 동적으로 로드하는 별도의 모듈을 만듭니다.\n\n```\n@NgModule()\nexport class EditorModule {\n constructor(@Inject(DOCUMENT) private document: Document) {}\n\n async load() {\n const style = document.createElement('style');\n style.textContent = require('../../assets/css/editor.css').default;\n this.document.head.appendChild(style);\n\n return require('../../assets/js/editor.js');\n }\n}\n```\n\n동적으로 다운로드할 모듈을 직접 사용하지 않아도 될 경우 코드를 생성자에 구현하면 됩니다. 예제 코드에서는 `editor.js`파일이 내보내는 함수를 직접 사용해야 하기 때문에 해당 모듈을 반환하는 별도의 메서드 `load`에 구현합니다. 모듈을 구현했으면 `angular.json` 파일에 해당 모듈을 등록합니다.\n\n```\n{\n \"projects\": {\n \"my-app\": {\n \"architect\": {\n \"build\": {\n \"lazyModules\": [\n \"src/app/modules/editor.module#EditorModule\"\n ]\n }\n }\n }\n }\n}\n```\n\n`lazyModules`의 배열에 해당 모듈 파일의 경로와 모듈의 이름을 #으로 구분해 기재합니다. 이후 이 프로젝트가 빌드될 때 `editor.module.ts`, `editor.css`, `editor.js`가 `src-app-modules-editor.module.js`로 분리되어 별도의 파일로 생성됩니다. 이제 아래의 코드로 위지윅 에디터의 생성자를 동적으로 얻어올 수 있습니다.\n\n```\n@Component({...})\nexport class AppComponent {\n title = 'app';\n @ViewChild('textarea') el: ElementRef;\n\n constructor(private injector: Injector, private loader: NgModuleFactoryLoader) {}\n\n onClickLoadEditor() {\n this.loader.load('src/app/modules/editor.module#EditorModule')\n .then(factory => factory.create(this.injector).instance.load())\n .then(({Editor}) => new Editor(this.el.nativeElement));\n }\n}\n```\n\n사실 Angular@v5 이하에서는 webpack이 기본적으로 사용했던 `System.import`파서 플러그인으로 `.ts`파일 뿐만 아닌 여러 파일을 동적으로 간단히 분리할 수 있었습니다. 하지만 [email protected] 부터 webpack이 `System.import`파서 플러그인을 사용하지 않게 되었고. Angular@v6 버전 이후부터는 해당 코드가 발견되면 컴파일 시점에 경고를 출력합니다. 그렇기 때문에 `System.import`를 직접적으로 사용할 수 없고 본문과 같이 `NgModuleFactoryLoader`를 사용해야 합니다.\n\n재미있는 것은 `NgModuleFactoryLoader`의 구현체인 `SystemJsNgModuleLoader`내부에서는 `System.import`를 아직 사용하고 있다는 것입니다. 공식 github에서는 이 코드를 typescript의 `import`문을 사용하는 것으로 수정하려는 PR이 있습니다. 이 PR이 머지된다고 하더라도. 위 방법을 이용하는 데 문제는 없습니다.",
"json_metadata": "{\"tags\":[\"angular\",\"angular2\",\"lazyloading\"],\"image\":[\"https://cdn.steemitimages.com/DQmeKHhZfrBdBqKy97xpbpnXqNv8EDt4oRuw3ouU1n1uwWZ/P5270018.jpg\"],\"links\":[\"http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular-route",
"title": "Angular에서 Route없이 모듈 동적 로딩하기"
}
],
"op_in_trx": 0,
"timestamp": "2018-06-05T09:08:06",
"trx_id": "2d82e847cdb4d8e844fcd4ca3b13b7076072ec99",
"trx_in_block": 11,
"virtual_op": 0
}2018/05/15 07:29:24
2018/05/15 07:29:24
| author | mnkim |
| permlink | angular |
| sbd payout | 0.014 SBD |
| steem payout | 0.000 STEEM |
| vesting payout | 10.175082 VESTS |
| Transaction Info | Block #22445695/Virtual Operation #14 |
View Raw JSON Data
{
"block": 22445695,
"op": [
"author_reward",
{
"author": "mnkim",
"permlink": "angular",
"sbd_payout": "0.014 SBD",
"steem_payout": "0.000 STEEM",
"vesting_payout": "10.175082 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2018-05-15T07:29:24",
"trx_id": "0000000000000000000000000000000000000000",
"trx_in_block": 4294967295,
"virtual_op": 14
}2018/05/15 04:34:12
2018/05/15 04:34:12
| author | mnkim |
| body | @@ -149,21 +149,16 @@ %EA%B3%B5%ED%95%98%EB%8B%88 -%EC%9D%B4%EB%9F%B0%EB%A9%B4%EC%97%90%EC%84%9C %ED%9B%A8%EC%94%AC %EC%A2%8B%EC%8A%B5%EB%8B%88%EB%8B%A4 +%ED%9B%A8%EC%94%AC %EC%A2%8B%EB%8D%94%EB%9D%BC%EA%B3%A0%EC%9A%94 .%0A%0AR @@ -194,16 +194,27 @@ lar%EA%B0%80 + %EA%B2%B0%EA%B3%BC%EC%A0%81%EC%9C%BC%EB%A1%9C %EB%8D%94 %ED%95%99%EC%8A%B5%EA%B3%A1%EC%84%A0%EC%9D%B4 +%EB%82%98 %EB%B9%84%EC%9A%A9%EC%9D%B4 %EB%82%AE%EC%9D%80%EA%B1%B0 |
| json metadata | {"tags":["angular"],"app":"steemit/0.1"} |
| parent author | woojin.joe |
| parent permlink | re-mnkim-angular-20180508t222709116z |
| permlink | re-woojinjoe-re-mnkim-angular-20180509t045821027z |
| title | |
| Transaction Info | Block #22442192/Trx 47ebab890e668e45a658a5ebb445b1fd0593f715 |
View Raw JSON Data
{
"block": 22442192,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -149,21 +149,16 @@\n %EA%B3%B5%ED%95%98%EB%8B%88 \n-%EC%9D%B4%EB%9F%B0%EB%A9%B4%EC%97%90%EC%84%9C %ED%9B%A8%EC%94%AC %EC%A2%8B%EC%8A%B5%EB%8B%88%EB%8B%A4\n+%ED%9B%A8%EC%94%AC %EC%A2%8B%EB%8D%94%EB%9D%BC%EA%B3%A0%EC%9A%94\n .%0A%0AR\n@@ -194,16 +194,27 @@\n lar%EA%B0%80\n+ %EA%B2%B0%EA%B3%BC%EC%A0%81%EC%9C%BC%EB%A1%9C\n %EB%8D%94 %ED%95%99%EC%8A%B5%EA%B3%A1%EC%84%A0%EC%9D%B4\n+%EB%82%98 %EB%B9%84%EC%9A%A9%EC%9D%B4\n %EB%82%AE%EC%9D%80%EA%B1%B0\n",
"json_metadata": "{\"tags\":[\"angular\"],\"app\":\"steemit/0.1\"}",
"parent_author": "woojin.joe",
"parent_permlink": "re-mnkim-angular-20180508t222709116z",
"permlink": "re-woojinjoe-re-mnkim-angular-20180509t045821027z",
"title": ""
}
],
"op_in_trx": 0,
"timestamp": "2018-05-15T04:34:12",
"trx_id": "47ebab890e668e45a658a5ebb445b1fd0593f715",
"trx_in_block": 8,
"virtual_op": 0
}2018/05/09 04:58:21
2018/05/09 04:58:21
| author | mnkim |
| body | React, Vue.js는 렌더링에 관련된 라이브러리만 제공되고 규모가 커질수록 서드파티 라이브러리를 사용해야 개발이 수월해지는데요. 이게 나중에 버전이 안맞는다던가 하는 등. 유지보수에 발목을 잡더군요. Angular는 그 자체로 웹 앱에 필요한 거의 모든것을 제공하니 이런면에서 훨씬 좋습니다. React, Angular둘 다 해본 입장에선 Angular가 더 학습곡선이 낮은거 같아요. |
| json metadata | {"tags":["angular"],"app":"steemit/0.1"} |
| parent author | woojin.joe |
| parent permlink | re-mnkim-angular-20180508t222709116z |
| permlink | re-woojinjoe-re-mnkim-angular-20180509t045821027z |
| title | |
| Transaction Info | Block #22269895/Trx f64e47e421d28c940752e92a13228a0530ed4c56 |
View Raw JSON Data
{
"block": 22269895,
"op": [
"comment",
{
"author": "mnkim",
"body": "React, Vue.js는 렌더링에 관련된 라이브러리만 제공되고 규모가 커질수록 서드파티 라이브러리를 사용해야 개발이 수월해지는데요. 이게 나중에 버전이 안맞는다던가 하는 등. 유지보수에 발목을 잡더군요. Angular는 그 자체로 웹 앱에 필요한 거의 모든것을 제공하니 이런면에서 훨씬 좋습니다.\n\nReact, Angular둘 다 해본 입장에선 Angular가 더 학습곡선이 낮은거 같아요.",
"json_metadata": "{\"tags\":[\"angular\"],\"app\":\"steemit/0.1\"}",
"parent_author": "woojin.joe",
"parent_permlink": "re-mnkim-angular-20180508t222709116z",
"permlink": "re-woojinjoe-re-mnkim-angular-20180509t045821027z",
"title": ""
}
],
"op_in_trx": 0,
"timestamp": "2018-05-09T04:58:21",
"trx_id": "f64e47e421d28c940752e92a13228a0530ed4c56",
"trx_in_block": 46,
"virtual_op": 0
}mnkimupvoted (100.00%) @woojin.joe / re-mnkim-angular-20180508t222709116z2018/05/09 04:51:54
mnkimupvoted (100.00%) @woojin.joe / re-mnkim-angular-20180508t222709116z
2018/05/09 04:51:54
| author | woojin.joe |
| permlink | re-mnkim-angular-20180508t222709116z |
| voter | mnkim |
| weight | 10000 (100.00%) |
| Transaction Info | Block #22269766/Trx 61228337032ac84a26639322e0c1c19e96d641b1 |
View Raw JSON Data
{
"block": 22269766,
"op": [
"vote",
{
"author": "woojin.joe",
"permlink": "re-mnkim-angular-20180508t222709116z",
"voter": "mnkim",
"weight": 10000
}
],
"op_in_trx": 0,
"timestamp": "2018-05-09T04:51:54",
"trx_id": "61228337032ac84a26639322e0c1c19e96d641b1",
"trx_in_block": 0,
"virtual_op": 0
}woojin.joereplied to @mnkim / re-mnkim-angular-20180508t222709116z2018/05/08 22:27:09
woojin.joereplied to @mnkim / re-mnkim-angular-20180508t222709116z
2018/05/08 22:27:09
| author | woojin.joe |
| body | 잘 봤습니다. :) 그래서 앵귤러 전도사(?) 역할을 하는 Minko Gechev가 DI기능만 쏙 빼서 이런것도 만들었죠. https://github.com/mgechev/injection-js 앵귤러가 리액트,뷰에 비해 학습곡선이 높지만 (저 같은 백엔드 엔지니어에겐) DI 등과 같이 기능적으로나 아키텍처측면에서 친숙한 것 같아요. |
| json metadata | {"tags":["angular"],"links":["https://github.com/mgechev/injection-js"],"app":"steemit/0.1"} |
| parent author | mnkim |
| parent permlink | angular |
| permlink | re-mnkim-angular-20180508t222709116z |
| title | |
| Transaction Info | Block #22262071/Trx 39f1f41323eb84e7aace3c57593d766739a9a9d1 |
View Raw JSON Data
{
"block": 22262071,
"op": [
"comment",
{
"author": "woojin.joe",
"body": "잘 봤습니다. :)\n그래서 앵귤러 전도사(?) 역할을 하는 Minko Gechev가 DI기능만 쏙 빼서 이런것도 만들었죠. \n\nhttps://github.com/mgechev/injection-js\n\n앵귤러가 리액트,뷰에 비해 학습곡선이 높지만 (저 같은 백엔드 엔지니어에겐) DI 등과 같이 기능적으로나 아키텍처측면에서 친숙한 것 같아요.",
"json_metadata": "{\"tags\":[\"angular\"],\"links\":[\"https://github.com/mgechev/injection-js\"],\"app\":\"steemit/0.1\"}",
"parent_author": "mnkim",
"parent_permlink": "angular",
"permlink": "re-mnkim-angular-20180508t222709116z",
"title": ""
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T22:27:09",
"trx_id": "39f1f41323eb84e7aace3c57593d766739a9a9d1",
"trx_in_block": 22,
"virtual_op": 0
}woojin.joeupvoted (100.00%) @mnkim / angular2018/05/08 22:21:36
woojin.joeupvoted (100.00%) @mnkim / angular
2018/05/08 22:21:36
| author | mnkim |
| permlink | angular |
| voter | woojin.joe |
| weight | 10000 (100.00%) |
| Transaction Info | Block #22261960/Trx 425bd65963f26cf213f62ab1c8b5e281537b8e27 |
View Raw JSON Data
{
"block": 22261960,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular",
"voter": "woojin.joe",
"weight": 10000
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T22:21:36",
"trx_id": "425bd65963f26cf213f62ab1c8b5e281537b8e27",
"trx_in_block": 9,
"virtual_op": 0
}2018/05/08 09:01:54
2018/05/08 09:01:54
| author | mnkim |
| body | @@ -946,16 +946,22 @@ %0A%7D%0A%60%60%60%0A%0A +----%0A%0A %60%60%60javas @@ -1644,19 +1644,32 @@ %0A/** -%0A * %5B%EC%B0%B8%EA%B3%A01%5D%0A +******** %5B%EC%B0%B8%EA%B3%A01%5D ********* */%0Av @@ -2080,27 +2080,32 @@ /** -%0A * %5B%EC%B0%B8%EA%B3%A02%5D%0A +******** %5B%EC%B0%B8%EA%B3%A02%5D ********* */%0A |
| json metadata | {"tags":["angular","javascript","typescript","di","dependencyinjection"],"links":["http://www.typescriptlang.org/docs/handbook/decorators.html#metadata","https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62","https://github.com/rbuckton/reflect-metadata"],"app":"steemit/0.1","format":"markdown","image":["https://steemitimages.com/DQmNiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq/P4280164%20(1).jpg"]} |
| parent author | |
| parent permlink | angular |
| permlink | angular |
| title | Angular는 클래스 생성에 필요한 인자들을 어떻게 알까 |
| Transaction Info | Block #22245967/Trx 6eb08fea14e8bd1ffcaa269facb1004db5ed4d8c |
View Raw JSON Data
{
"block": 22245967,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -946,16 +946,22 @@\n %0A%7D%0A%60%60%60%0A%0A\n+----%0A%0A\n %60%60%60javas\n@@ -1644,19 +1644,32 @@\n %0A/**\n-%0A * %5B%EC%B0%B8%EA%B3%A01%5D%0A \n+******** %5B%EC%B0%B8%EA%B3%A01%5D *********\n */%0Av\n@@ -2080,27 +2080,32 @@\n /**\n-%0A * %5B%EC%B0%B8%EA%B3%A02%5D%0A \n+******** %5B%EC%B0%B8%EA%B3%A02%5D *********\n */%0A \n",
"json_metadata": "{\"tags\":[\"angular\",\"javascript\",\"typescript\",\"di\",\"dependencyinjection\"],\"links\":[\"http://www.typescriptlang.org/docs/handbook/decorators.html#metadata\",\"https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62\",\"https://github.com/rbuckton/reflect-metadata\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\",\"image\":[\"https://steemitimages.com/DQmNiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq/P4280164%20(1).jpg\"]}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular",
"title": "Angular는 클래스 생성에 필요한 인자들을 어떻게 알까"
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T09:01:54",
"trx_id": "6eb08fea14e8bd1ffcaa269facb1004db5ed4d8c",
"trx_in_block": 51,
"virtual_op": 0
}2018/05/08 08:42:12
2018/05/08 08:42:12
| author | mnkim |
| permlink | angular |
| voter | dongkun |
| weight | 10000 (100.00%) |
| Transaction Info | Block #22245573/Trx 313bbd16d2826049f4e4ee5d3df25fb3272c60d4 |
View Raw JSON Data
{
"block": 22245573,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular",
"voter": "dongkun",
"weight": 10000
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T08:42:12",
"trx_id": "313bbd16d2826049f4e4ee5d3df25fb3272c60d4",
"trx_in_block": 55,
"virtual_op": 0
}2018/05/08 08:30:54
2018/05/08 08:30:54
| author | mnkim |
| body | @@ -2933,16 +2933,17 @@ API%EC%9E%85%EB%8B%88%EB%8B%A4. +%5B Typescri @@ -2949,16 +2949,87 @@ ipt%EA%B3%B5%EC%8B%9D %EB%AC%B8%EC%84%9C +%5D(http://www.typescriptlang.org/docs/handbook/decorators.html#metadata) %EC%97%90%EC%84%9C%EB%8A%94 Deco |
| json metadata | {"tags":["angular","javascript","typescript","di","dependencyinjection"],"links":["http://www.typescriptlang.org/docs/handbook/decorators.html#metadata","https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62","https://github.com/rbuckton/reflect-metadata"],"app":"steemit/0.1","format":"markdown","image":["https://steemitimages.com/DQmNiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq/P4280164%20(1).jpg"]} |
| parent author | |
| parent permlink | angular |
| permlink | angular |
| title | Angular는 클래스 생성에 필요한 인자들을 어떻게 알까 |
| Transaction Info | Block #22245347/Trx 9e644195195fb9b8be059fbbd421859d31a6424c |
View Raw JSON Data
{
"block": 22245347,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -2933,16 +2933,17 @@\n API%EC%9E%85%EB%8B%88%EB%8B%A4. \n+%5B\n Typescri\n@@ -2949,16 +2949,87 @@\n ipt%EA%B3%B5%EC%8B%9D %EB%AC%B8%EC%84%9C\n+%5D(http://www.typescriptlang.org/docs/handbook/decorators.html#metadata)\n %EC%97%90%EC%84%9C%EB%8A%94 Deco\n",
"json_metadata": "{\"tags\":[\"angular\",\"javascript\",\"typescript\",\"di\",\"dependencyinjection\"],\"links\":[\"http://www.typescriptlang.org/docs/handbook/decorators.html#metadata\",\"https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62\",\"https://github.com/rbuckton/reflect-metadata\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\",\"image\":[\"https://steemitimages.com/DQmNiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq/P4280164%20(1).jpg\"]}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular",
"title": "Angular는 클래스 생성에 필요한 인자들을 어떻게 알까"
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T08:30:54",
"trx_id": "9e644195195fb9b8be059fbbd421859d31a6424c",
"trx_in_block": 15,
"virtual_op": 0
}2018/05/08 08:21:09
2018/05/08 08:21:09
| author | mnkim |
| body | @@ -1,22 +1,26 @@ !%5BP4280164 + (1) .jpg%5D(https: @@ -46,52 +46,52 @@ /DQm -YC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o +NiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq /P42 @@ -95,16 +95,22 @@ P4280164 +%2520(1) .jpg)%0A%0A%EC%9D%98 |
| json metadata | {"tags":["angular","javascript","typescript","di","dependencyinjection"],"links":["https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62","https://github.com/rbuckton/reflect-metadata"],"app":"steemit/0.1","format":"markdown","image":["https://steemitimages.com/DQmNiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq/P4280164%20(1).jpg"]} |
| parent author | |
| parent permlink | angular |
| permlink | angular |
| title | Angular는 클래스 생성에 필요한 인자들을 어떻게 알까 |
| Transaction Info | Block #22245152/Trx 998c0c4566cd9aae23a0a52e0d8138e4075748a4 |
View Raw JSON Data
{
"block": 22245152,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -1,22 +1,26 @@\n !%5BP4280164\n+ (1)\n .jpg%5D(https:\n@@ -46,52 +46,52 @@\n /DQm\n-YC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o\n+NiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq\n /P42\n@@ -95,16 +95,22 @@\n P4280164\n+%2520(1)\n .jpg)%0A%0A%EC%9D%98\n",
"json_metadata": "{\"tags\":[\"angular\",\"javascript\",\"typescript\",\"di\",\"dependencyinjection\"],\"links\":[\"https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62\",\"https://github.com/rbuckton/reflect-metadata\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\",\"image\":[\"https://steemitimages.com/DQmNiYjKBVhCZdwFeYoHB2MhpnKNq8wjbijAFQj241kKfGq/P4280164%20(1).jpg\"]}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular",
"title": "Angular는 클래스 생성에 필요한 인자들을 어떻게 알까"
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T08:21:09",
"trx_id": "998c0c4566cd9aae23a0a52e0d8138e4075748a4",
"trx_in_block": 22,
"virtual_op": 0
}2018/05/08 08:20:06
2018/05/08 08:20:06
| author | mnkim |
| body |  의존성 주입 패턴은 Angular의 핵심 시스템입니다. 이 패턴으로 각 모듈은 더 이상 다른 모듈을 직접 참조하거나 생성하지 않습니다. 필요한 모듈은 일반적으로 '컨테이너'라 불리는 별도의 인스턴스 관리 객체로 부터 주입받습니다. 이 의존성 주입 시스템은 사실 순수하게 Angular의 기능은 아닙니다. Javascript를 래핑해 타입 시스템을 추가한 언어인 Typescript와 proposal 단계의 ECMASscript 스펙 `reflect-metadata`가 이 패턴이 동작하는 데 필요한 역할들을 하고 있습니다. 의존성 주입 시스템의 필요한 조건들 중 하나는 어떤 클래스가 생성될 때 어떤 인자를 필요로 하는지 알고 있어야 한다는 것입니다. 이 글이 쓰여질 때 ECMAScript의 최신 버전인 2018 에도 아직 해당 스펙이 존재하거나 논의되지 않고 있습니다. 따라서 순수한 Javascript만으로는 별도의 처리 없이 이 패턴을 구현하기가 까다롭습니다. 따라서 Typescript와 같은 트랜스파일러가 꼭 필요합니다. Typescript는 Decorator가 달린 클래스를 트랜스파일 할 때 이를 처리하기 위한 폴리필 함수를 소스에 추가합니다 1). 아래는 Typescript소스와 이를 트랜스파일한 소스입니다. 1) 공식 문서에 따르면 Decorator와 Metadata를 사용하려면 tsconfig.json에 experimentalDecorators, emitDecoratorMetadata옵션을 true로 설정해야 합니다. ```typescript // User.ts @log class User { constructor(name: string) {} } ``` ```javascript // bundle.js "use strict"; var __decorate = this && this.__decorate || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) { if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; }return c > 3 && r && Object.defineProperty(target, key, r), r; }; /** * [참고1] */ var __metadata = this && this.__metadata || function (k, v) { if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); var User = /** @class */function () { function User(name) {} User = __decorate([ decorators_1.forClass, /** * [참고2] */ __metadata("design:paramtypes", [String]) ], User); return User; }(); ``` 트랜스파일 된 소스엔 원본 파일에 있는 소스 말고도 `__decorate`와 `__metadata`라는 두 함수가 추가로 정의되어 있습니다. `__decorate`함수는 `@log`의 기능을 `User` 클래스에 적용하기 위한 폴리필 함수입니다. 아래에서 `User`클래스를 생성할 때 `log` `Decorator`를 배열에 담아 인자로 호출하고 있습니다. `Decorator`가 달린 클래스들은 전부 동일하게 트랜스파일됩니다. `__metadata`함수*[참고1]*는 이 글의 주제인 의존성 주입 패턴과 밀접한 관련이 있습니다. 강조된 코드에서 `__metadata`함수에 `"design:paramtypes"` 리터럴 문자열과 배열로 `String` 클래스를 넘기는 것을 볼 수 있습니다. *[참고2]* 이 정보가 바로 `User`클래스 생성자 함수의 인자에 대한 정보입니다. 이어서 `__metadata`함수는 전달받은 생성자 파라미터 정보를 그대로 `Reflect.metadata`함수의 인자로 호출하고 있습니다. 이렇게 메타데이터가 등록된 후 아래의 코드를 실행하면 앞서 언급했던 조건인 `User`클래스의 생성자가 어떤 인자를 필요로 하는지에 대한 정보를 얻을 수 있습니다. ```typescript Reflect.getMedata('design':paramtypes', User); // log: [String] ``` `reflect-metadata` API는 `TC39`에 아직 등록조자 되지 않은 Experimental 상태의 비표준 API입니다. Typescript공식 문서에서는 Decorator가 표준이 될 때 아마 같이 표준으로 등록될 것이라고 안내하고 있습니다. 실제로 [`ReflectionCapabilities`클래스 내부 구현](https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62)을 보면 Angular가 해당 API를 사용하고 있는 것을 볼 수 있습니다. `reflect-metadata`말고도 direct API, tsickle등의 도구에서 분석된 파라미터도 참고하고 있는 것을 볼 수 있습니다만. 기본적인 방식은 같습니다. 참고 - `reflect-metadata` https://github.com/rbuckton/reflect-metadata |
| json metadata | {"tags":["angular","javascript","typescript","di","dependencyinjection"],"links":["https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62","https://github.com/rbuckton/reflect-metadata"],"app":"steemit/0.1","format":"markdown","image":["https://steemitimages.com/DQmYC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o/P4280164.jpg"]} |
| parent author | |
| parent permlink | angular |
| permlink | angular |
| title | Angular는 클래스 생성에 필요한 인자들을 어떻게 알까 |
| Transaction Info | Block #22245131/Trx 0ab9587eb59ca3ff6234c177abdf1fa7ba4d4df5 |
View Raw JSON Data
{
"block": 22245131,
"op": [
"comment",
{
"author": "mnkim",
"body": "\n\n의존성 주입 패턴은 Angular의 핵심 시스템입니다. 이 패턴으로 각 모듈은 더 이상 다른 모듈을 직접 참조하거나 생성하지 않습니다. 필요한 모듈은 일반적으로 '컨테이너'라 불리는 별도의 인스턴스 관리 객체로 부터 주입받습니다.\n\n이 의존성 주입 시스템은 사실 순수하게 Angular의 기능은 아닙니다. Javascript를 래핑해 타입 시스템을 추가한 언어인 Typescript와 proposal 단계의 ECMASscript 스펙 `reflect-metadata`가 이 패턴이 동작하는 데 필요한 역할들을 하고 있습니다.\n\n의존성 주입 시스템의 필요한 조건들 중 하나는 어떤 클래스가 생성될 때 어떤 인자를 필요로 하는지 알고 있어야 한다는 것입니다. 이 글이 쓰여질 때 ECMAScript의 최신 버전인 2018 에도 아직 해당 스펙이 존재하거나 논의되지 않고 있습니다. 따라서 순수한 Javascript만으로는 별도의 처리 없이 이 패턴을 구현하기가 까다롭습니다. 따라서 Typescript와 같은 트랜스파일러가 꼭 필요합니다.\n\nTypescript는 Decorator가 달린 클래스를 트랜스파일 할 때 이를 처리하기 위한 폴리필 함수를 소스에 추가합니다 1). 아래는 Typescript소스와 이를 트랜스파일한 소스입니다.\n\n1) 공식 문서에 따르면 Decorator와 Metadata를 사용하려면 tsconfig.json에 experimentalDecorators, emitDecoratorMetadata옵션을 true로 설정해야 합니다.\n\n```typescript\n// User.ts\n@log\nclass User {\n constructor(name: string) {}\n}\n```\n\n```javascript\n// bundle.js\n\"use strict\";\nvar __decorate = this && this.__decorate || function (decorators, target, key, desc) {\n var c = arguments.length,\n r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,\n d;\n if ((typeof Reflect === \"undefined\" ? \"undefined\" : _typeof(Reflect)) === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) {\n if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n }return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\n\n/**\n * [참고1]\n */\nvar __metadata = this && this.__metadata || function (k, v) {\n if ((typeof Reflect === \"undefined\" ? \"undefined\" : _typeof(Reflect)) === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\n\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar User = /** @class */function () {\n function User(name) {}\n User = __decorate([\n decorators_1.forClass,\n /**\n * [참고2]\n */\n __metadata(\"design:paramtypes\", [String])\n ], User);\n return User;\n}();\n```\n\n트랜스파일 된 소스엔 원본 파일에 있는 소스 말고도 `__decorate`와 `__metadata`라는 두 함수가 추가로 정의되어 있습니다.\n\n`__decorate`함수는 `@log`의 기능을 `User` 클래스에 적용하기 위한 폴리필 함수입니다. 아래에서 `User`클래스를 생성할 때 `log` `Decorator`를 배열에 담아 인자로 호출하고 있습니다. `Decorator`가 달린 클래스들은 전부 동일하게 트랜스파일됩니다.\n\n`__metadata`함수*[참고1]*는 이 글의 주제인 의존성 주입 패턴과 밀접한 관련이 있습니다. 강조된 코드에서 `__metadata`함수에 `\"design:paramtypes\"` 리터럴 문자열과 배열로 `String` 클래스를 넘기는 것을 볼 수 있습니다. *[참고2]* 이 정보가 바로 `User`클래스 생성자 함수의 인자에 대한 정보입니다.\n\n이어서 `__metadata`함수는 전달받은 생성자 파라미터 정보를 그대로 `Reflect.metadata`함수의 인자로 호출하고 있습니다. 이렇게 메타데이터가 등록된 후 아래의 코드를 실행하면 앞서 언급했던 조건인 `User`클래스의 생성자가 어떤 인자를 필요로 하는지에 대한 정보를 얻을 수 있습니다.\n\n```typescript\nReflect.getMedata('design':paramtypes', User);\n// log: [String]\n```\n\n`reflect-metadata` API는 `TC39`에 아직 등록조자 되지 않은 Experimental 상태의 비표준 API입니다. Typescript공식 문서에서는 Decorator가 표준이 될 때 아마 같이 표준으로 등록될 것이라고 안내하고 있습니다.\n\n실제로 [`ReflectionCapabilities`클래스 내부 구현](https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62)을 보면 Angular가 해당 API를 사용하고 있는 것을 볼 수 있습니다. `reflect-metadata`말고도 direct API, tsickle등의 도구에서 분석된 파라미터도 참고하고 있는 것을 볼 수 있습니다만. 기본적인 방식은 같습니다.\n\n참고\n\n- `reflect-metadata` https://github.com/rbuckton/reflect-metadata",
"json_metadata": "{\"tags\":[\"angular\",\"javascript\",\"typescript\",\"di\",\"dependencyinjection\"],\"links\":[\"https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62\",\"https://github.com/rbuckton/reflect-metadata\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\",\"image\":[\"https://steemitimages.com/DQmYC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o/P4280164.jpg\"]}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular",
"title": "Angular는 클래스 생성에 필요한 인자들을 어떻게 알까"
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T08:20:06",
"trx_id": "0ab9587eb59ca3ff6234c177abdf1fa7ba4d4df5",
"trx_in_block": 46,
"virtual_op": 0
}2018/05/08 08:19:03
2018/05/08 08:19:03
| author | mnkim |
| body | @@ -1,16 +1,121 @@ +!%5BP4280164.jpg%5D(https://steemitimages.com/DQmYC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o/P4280164.jpg)%0A%0A %EC%9D%98%EC%A1%B4%EC%84%B1 %EC%A3%BC%EC%9E%85 %ED%8C%A8%ED%84%B4%EC%9D%80 Angul |
| json metadata | {"tags":["angular","javascript","typescript","di","dependencyinjection"],"links":["https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62","https://github.com/rbuckton/reflect-metadata"],"app":"steemit/0.1","format":"markdown","image":["https://steemitimages.com/DQmYC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o/P4280164.jpg"]} |
| parent author | |
| parent permlink | angular |
| permlink | angular |
| title | Angular는 클래스 생성에 필요한 인자들을 어떻게 알까 |
| Transaction Info | Block #22245110/Trx 166b993cb450b330e2532d7c322032cf9cab808b |
View Raw JSON Data
{
"block": 22245110,
"op": [
"comment",
{
"author": "mnkim",
"body": "@@ -1,16 +1,121 @@\n+!%5BP4280164.jpg%5D(https://steemitimages.com/DQmYC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o/P4280164.jpg)%0A%0A\n %EC%9D%98%EC%A1%B4%EC%84%B1 %EC%A3%BC%EC%9E%85 %ED%8C%A8%ED%84%B4%EC%9D%80 Angul\n",
"json_metadata": "{\"tags\":[\"angular\",\"javascript\",\"typescript\",\"di\",\"dependencyinjection\"],\"links\":[\"https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62\",\"https://github.com/rbuckton/reflect-metadata\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\",\"image\":[\"https://steemitimages.com/DQmYC1jHE29iZTJSuxUdxTQjB77gKUNSzj3gJyeNHzzXs8o/P4280164.jpg\"]}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular",
"title": "Angular는 클래스 생성에 필요한 인자들을 어떻게 알까"
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T08:19:03",
"trx_id": "166b993cb450b330e2532d7c322032cf9cab808b",
"trx_in_block": 46,
"virtual_op": 0
}2018/05/08 07:29:33
2018/05/08 07:29:33
| author | mnkim |
| permlink | angular |
| voter | ax3 |
| weight | 100 (1.00%) |
| Transaction Info | Block #22244120/Trx 6a23f2f0766d120322101d976017a491a7f02513 |
View Raw JSON Data
{
"block": 22244120,
"op": [
"vote",
{
"author": "mnkim",
"permlink": "angular",
"voter": "ax3",
"weight": 100
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T07:29:33",
"trx_id": "6a23f2f0766d120322101d976017a491a7f02513",
"trx_in_block": 12,
"virtual_op": 0
}2018/05/08 07:29:24
2018/05/08 07:29:24
| author | mnkim |
| body | 의존성 주입 패턴은 Angular의 핵심 시스템입니다. 이 패턴으로 각 모듈은 더 이상 다른 모듈을 직접 참조하거나 생성하지 않습니다. 필요한 모듈은 일반적으로 '컨테이너'라 불리는 별도의 인스턴스 관리 객체로 부터 주입받습니다. 이 의존성 주입 시스템은 사실 순수하게 Angular의 기능은 아닙니다. Javascript를 래핑해 타입 시스템을 추가한 언어인 Typescript와 proposal 단계의 ECMASscript 스펙 `reflect-metadata`가 이 패턴이 동작하는 데 필요한 역할들을 하고 있습니다. 의존성 주입 시스템의 필요한 조건들 중 하나는 어떤 클래스가 생성될 때 어떤 인자를 필요로 하는지 알고 있어야 한다는 것입니다. 이 글이 쓰여질 때 ECMAScript의 최신 버전인 2018 에도 아직 해당 스펙이 존재하거나 논의되지 않고 있습니다. 따라서 순수한 Javascript만으로는 별도의 처리 없이 이 패턴을 구현하기가 까다롭습니다. 따라서 Typescript와 같은 트랜스파일러가 꼭 필요합니다. Typescript는 Decorator가 달린 클래스를 트랜스파일 할 때 이를 처리하기 위한 폴리필 함수를 소스에 추가합니다 1). 아래는 Typescript소스와 이를 트랜스파일한 소스입니다. 1) 공식 문서에 따르면 Decorator와 Metadata를 사용하려면 tsconfig.json에 experimentalDecorators, emitDecoratorMetadata옵션을 true로 설정해야 합니다. ```typescript // User.ts @log class User { constructor(name: string) {} } ``` ```javascript // bundle.js "use strict"; var __decorate = this && this.__decorate || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) { if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; }return c > 3 && r && Object.defineProperty(target, key, r), r; }; /** * [참고1] */ var __metadata = this && this.__metadata || function (k, v) { if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); var User = /** @class */function () { function User(name) {} User = __decorate([ decorators_1.forClass, /** * [참고2] */ __metadata("design:paramtypes", [String]) ], User); return User; }(); ``` 트랜스파일 된 소스엔 원본 파일에 있는 소스 말고도 `__decorate`와 `__metadata`라는 두 함수가 추가로 정의되어 있습니다. `__decorate`함수는 `@log`의 기능을 `User` 클래스에 적용하기 위한 폴리필 함수입니다. 아래에서 `User`클래스를 생성할 때 `log` `Decorator`를 배열에 담아 인자로 호출하고 있습니다. `Decorator`가 달린 클래스들은 전부 동일하게 트랜스파일됩니다. `__metadata`함수*[참고1]*는 이 글의 주제인 의존성 주입 패턴과 밀접한 관련이 있습니다. 강조된 코드에서 `__metadata`함수에 `"design:paramtypes"` 리터럴 문자열과 배열로 `String` 클래스를 넘기는 것을 볼 수 있습니다. *[참고2]* 이 정보가 바로 `User`클래스 생성자 함수의 인자에 대한 정보입니다. 이어서 `__metadata`함수는 전달받은 생성자 파라미터 정보를 그대로 `Reflect.metadata`함수의 인자로 호출하고 있습니다. 이렇게 메타데이터가 등록된 후 아래의 코드를 실행하면 앞서 언급했던 조건인 `User`클래스의 생성자가 어떤 인자를 필요로 하는지에 대한 정보를 얻을 수 있습니다. ```typescript Reflect.getMedata('design':paramtypes', User); // log: [String] ``` `reflect-metadata` API는 `TC39`에 아직 등록조자 되지 않은 Experimental 상태의 비표준 API입니다. Typescript공식 문서에서는 Decorator가 표준이 될 때 아마 같이 표준으로 등록될 것이라고 안내하고 있습니다. 실제로 [`ReflectionCapabilities`클래스 내부 구현](https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62)을 보면 Angular가 해당 API를 사용하고 있는 것을 볼 수 있습니다. `reflect-metadata`말고도 direct API, tsickle등의 도구에서 분석된 파라미터도 참고하고 있는 것을 볼 수 있습니다만. 기본적인 방식은 같습니다. 참고 - `reflect-metadata` https://github.com/rbuckton/reflect-metadata |
| json metadata | {"tags":["angular","javascript","typescript","di","dependencyinjection"],"links":["https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62","https://github.com/rbuckton/reflect-metadata"],"app":"steemit/0.1","format":"markdown"} |
| parent author | |
| parent permlink | angular |
| permlink | angular |
| title | Angular는 클래스 생성에 필요한 인자들을 어떻게 알까 |
| Transaction Info | Block #22244117/Trx 8b0448273b4f7f6843c6abf1736e8d391707c724 |
View Raw JSON Data
{
"block": 22244117,
"op": [
"comment",
{
"author": "mnkim",
"body": "의존성 주입 패턴은 Angular의 핵심 시스템입니다. 이 패턴으로 각 모듈은 더 이상 다른 모듈을 직접 참조하거나 생성하지 않습니다. 필요한 모듈은 일반적으로 '컨테이너'라 불리는 별도의 인스턴스 관리 객체로 부터 주입받습니다.\n\n이 의존성 주입 시스템은 사실 순수하게 Angular의 기능은 아닙니다. Javascript를 래핑해 타입 시스템을 추가한 언어인 Typescript와 proposal 단계의 ECMASscript 스펙 `reflect-metadata`가 이 패턴이 동작하는 데 필요한 역할들을 하고 있습니다.\n\n의존성 주입 시스템의 필요한 조건들 중 하나는 어떤 클래스가 생성될 때 어떤 인자를 필요로 하는지 알고 있어야 한다는 것입니다. 이 글이 쓰여질 때 ECMAScript의 최신 버전인 2018 에도 아직 해당 스펙이 존재하거나 논의되지 않고 있습니다. 따라서 순수한 Javascript만으로는 별도의 처리 없이 이 패턴을 구현하기가 까다롭습니다. 따라서 Typescript와 같은 트랜스파일러가 꼭 필요합니다.\n\nTypescript는 Decorator가 달린 클래스를 트랜스파일 할 때 이를 처리하기 위한 폴리필 함수를 소스에 추가합니다 1). 아래는 Typescript소스와 이를 트랜스파일한 소스입니다.\n\n1) 공식 문서에 따르면 Decorator와 Metadata를 사용하려면 tsconfig.json에 experimentalDecorators, emitDecoratorMetadata옵션을 true로 설정해야 합니다.\n\n```typescript\n// User.ts\n@log\nclass User {\n constructor(name: string) {}\n}\n```\n\n```javascript\n// bundle.js\n\"use strict\";\nvar __decorate = this && this.__decorate || function (decorators, target, key, desc) {\n var c = arguments.length,\n r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,\n d;\n if ((typeof Reflect === \"undefined\" ? \"undefined\" : _typeof(Reflect)) === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) {\n if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n }return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\n\n/**\n * [참고1]\n */\nvar __metadata = this && this.__metadata || function (k, v) {\n if ((typeof Reflect === \"undefined\" ? \"undefined\" : _typeof(Reflect)) === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\n\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar User = /** @class */function () {\n function User(name) {}\n User = __decorate([\n decorators_1.forClass,\n /**\n * [참고2]\n */\n __metadata(\"design:paramtypes\", [String])\n ], User);\n return User;\n}();\n```\n\n트랜스파일 된 소스엔 원본 파일에 있는 소스 말고도 `__decorate`와 `__metadata`라는 두 함수가 추가로 정의되어 있습니다.\n\n`__decorate`함수는 `@log`의 기능을 `User` 클래스에 적용하기 위한 폴리필 함수입니다. 아래에서 `User`클래스를 생성할 때 `log` `Decorator`를 배열에 담아 인자로 호출하고 있습니다. `Decorator`가 달린 클래스들은 전부 동일하게 트랜스파일됩니다.\n\n`__metadata`함수*[참고1]*는 이 글의 주제인 의존성 주입 패턴과 밀접한 관련이 있습니다. 강조된 코드에서 `__metadata`함수에 `\"design:paramtypes\"` 리터럴 문자열과 배열로 `String` 클래스를 넘기는 것을 볼 수 있습니다. *[참고2]* 이 정보가 바로 `User`클래스 생성자 함수의 인자에 대한 정보입니다.\n\n이어서 `__metadata`함수는 전달받은 생성자 파라미터 정보를 그대로 `Reflect.metadata`함수의 인자로 호출하고 있습니다. 이렇게 메타데이터가 등록된 후 아래의 코드를 실행하면 앞서 언급했던 조건인 `User`클래스의 생성자가 어떤 인자를 필요로 하는지에 대한 정보를 얻을 수 있습니다.\n\n```typescript\nReflect.getMedata('design':paramtypes', User);\n// log: [String]\n```\n\n`reflect-metadata` API는 `TC39`에 아직 등록조자 되지 않은 Experimental 상태의 비표준 API입니다. Typescript공식 문서에서는 Decorator가 표준이 될 때 아마 같이 표준으로 등록될 것이라고 안내하고 있습니다.\n\n실제로 [`ReflectionCapabilities`클래스 내부 구현](https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62)을 보면 Angular가 해당 API를 사용하고 있는 것을 볼 수 있습니다. `reflect-metadata`말고도 direct API, tsickle등의 도구에서 분석된 파라미터도 참고하고 있는 것을 볼 수 있습니다만. 기본적인 방식은 같습니다.\n\n참고\n\n- `reflect-metadata` https://github.com/rbuckton/reflect-metadata",
"json_metadata": "{\"tags\":[\"angular\",\"javascript\",\"typescript\",\"di\",\"dependencyinjection\"],\"links\":[\"https://github.com/angular/angular/blob/b7544cccc699c2274bbc9a3e2eb4351632d0b410/packages/core/src/reflection/reflection_capabilities.ts#L62\",\"https://github.com/rbuckton/reflect-metadata\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}",
"parent_author": "",
"parent_permlink": "angular",
"permlink": "angular",
"title": "Angular는 클래스 생성에 필요한 인자들을 어떻게 알까"
}
],
"op_in_trx": 0,
"timestamp": "2018-05-08T07:29:24",
"trx_id": "8b0448273b4f7f6843c6abf1736e8d391707c724",
"trx_in_block": 41,
"virtual_op": 0
}2018/04/12 02:54:30
2018/04/12 02:54:30
| delegatee | mnkim |
| delegator | steem |
| vesting shares | 30373.861677 VESTS |
| Transaction Info | Block #21490628/Trx 3715c3e2bf295faa0d966c0545852b04db2450b9 |
View Raw JSON Data
{
"block": 21490628,
"op": [
"delegate_vesting_shares",
{
"delegatee": "mnkim",
"delegator": "steem",
"vesting_shares": "30373.861677 VESTS"
}
],
"op_in_trx": 0,
"timestamp": "2018-04-12T02:54:30",
"trx_id": "3715c3e2bf295faa0d966c0545852b04db2450b9",
"trx_in_block": 34,
"virtual_op": 0
}2018/04/12 00:47:48
2018/04/12 00:47:48
| active | {"account_auths":[],"key_auths":[["STM85PsTh3MXSxG8hspgT4LoQrpayLqHiMSRGFVufs9rnY5cAi1VZ",1]],"weight_threshold":1} |
| creator | steem |
| delegation | 30690.000000 VESTS |
| extensions | [] |
| fee | 0.100 STEEM |
| json metadata | {} |
| memo key | STM7NCpqSwzRLX8fCWvoyCaLsVCBBbLEYoiJA9vtFk4KKemk1BitM |
| new account name | mnkim |
| owner | {"account_auths":[],"key_auths":[["STM83T3qMZ6smHSVkVu9bzsfZYmkuB8HTr7UaPBhCd2jcAcX1xxAC",1]],"weight_threshold":1} |
| posting | {"account_auths":[],"key_auths":[["STM6adjVawMAg7bnZaGoxxqs2CEQdq16HvpAcfrhZ7PWtAdQpRVRb",1]],"weight_threshold":1} |
| Transaction Info | Block #21488095/Trx 079a7ed852555fe985ec1e0a7e23c7b70d115fdf |
View Raw JSON Data
{
"block": 21488095,
"op": [
"account_create_with_delegation",
{
"active": {
"account_auths": [],
"key_auths": [
[
"STM85PsTh3MXSxG8hspgT4LoQrpayLqHiMSRGFVufs9rnY5cAi1VZ",
1
]
],
"weight_threshold": 1
},
"creator": "steem",
"delegation": "30690.000000 VESTS",
"extensions": [],
"fee": "0.100 STEEM",
"json_metadata": "{}",
"memo_key": "STM7NCpqSwzRLX8fCWvoyCaLsVCBBbLEYoiJA9vtFk4KKemk1BitM",
"new_account_name": "mnkim",
"owner": {
"account_auths": [],
"key_auths": [
[
"STM83T3qMZ6smHSVkVu9bzsfZYmkuB8HTr7UaPBhCd2jcAcX1xxAC",
1
]
],
"weight_threshold": 1
},
"posting": {
"account_auths": [],
"key_auths": [
[
"STM6adjVawMAg7bnZaGoxxqs2CEQdq16HvpAcfrhZ7PWtAdQpRVRb",
1
]
],
"weight_threshold": 1
}
}
],
"op_in_trx": 0,
"timestamp": "2018-04-12T00:47:48",
"trx_id": "079a7ed852555fe985ec1e0a7e23c7b70d115fdf",
"trx_in_block": 4,
"virtual_op": 0
}Manabar
Voting Power100.00%
Downvote Power100.00%
Resource Credits100.00%
Reputation Progress0.00%
{
"voting_manabar": {
"current_mana": "8143659806",
"last_update_time": 1779076533
},
"downvote_manabar": {
"current_mana": 2035914951,
"last_update_time": 1779076533
},
"rc_account": {
"account": "mnkim",
"rc_manabar": {
"current_mana": "10164408779",
"last_update_time": 1779076533
},
"max_rc_creation_adjustment": {
"amount": "2020748973",
"precision": 6,
"nai": "@@000000037"
},
"max_rc": "10164408779"
}
}Account Metadata
| POSTING JSON METADATA | |
| None | |
| JSON METADATA | |
| None |
{
"posting_json_metadata": {},
"json_metadata": {}
}Auth Keys
Owner
Single Signature
Public Keys
STM83T3qMZ6smHSVkVu9bzsfZYmkuB8HTr7UaPBhCd2jcAcX1xxAC1/1
Active
Single Signature
Public Keys
STM85PsTh3MXSxG8hspgT4LoQrpayLqHiMSRGFVufs9rnY5cAi1VZ1/1
Posting
Single Signature
Public Keys
STM6adjVawMAg7bnZaGoxxqs2CEQdq16HvpAcfrhZ7PWtAdQpRVRb1/1
Memo
STM7NCpqSwzRLX8fCWvoyCaLsVCBBbLEYoiJA9vtFk4KKemk1BitM
{
"owner": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM83T3qMZ6smHSVkVu9bzsfZYmkuB8HTr7UaPBhCd2jcAcX1xxAC",
1
]
]
},
"active": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM85PsTh3MXSxG8hspgT4LoQrpayLqHiMSRGFVufs9rnY5cAi1VZ",
1
]
]
},
"posting": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM6adjVawMAg7bnZaGoxxqs2CEQdq16HvpAcfrhZ7PWtAdQpRVRb",
1
]
]
},
"memo": "STM7NCpqSwzRLX8fCWvoyCaLsVCBBbLEYoiJA9vtFk4KKemk1BitM"
}Witness Votes
0 / 30
No active witness votes.
[]