Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

React Native GUIDE

679 views

Published on

React Native 入門用の話がそこそこ
裏側を覗く部分がメインです
以下のコードの解説をしています
- react-native init
- react-native run-ios

Published in: Engineering
  • Be the first to comment

React Native GUIDE

  1. 1. React Native GUIDE ⼊⾨からその裏側まで覗いてみよう
  2. 2. About Me
  3. 3. ビズリーチ・ キャンパス 学⽣、OB/OG 向けサイト • Java8+Spring Boot (Thymeleaf) • ES2015+KnockoutJS 社内管理者向けサイト • Java8+Spring Boot • ES2015+React(+Redux) アプリ • Java8+Spring Boot • Swift
  4. 4. React とは
  5. 5. React とは 1/3 https://facebook.github.io/react/ Facebook 製 • UI 構築⽤の JavaScript ライブラリ • Declarative(宣⾔的) – アプリの状態に応じたインタラクティブ な UI を簡単に構築できる – コードもわかりやすい • Component-Based – いわゆるコンポーネント(部品)指向 – ⾃分⾃⾝の状態も管理する • Learn Once,Write Anywhere – これだけ覚えればサーバサイドもスマホ アプリも OK
  6. 6. React とは 2/3 https://speakerdeck.com/katamu ki/es2015-react-dot-jswoxue-bu 弊社のおっさんが学んだ話(宣伝) • コンポーネントを組み合わせて構築す るコンポーネント指向の View ライブ ラリ • Facebook、インスタ、Yahoo!、 Airbnb などでも使われている • VirtualDOMを⽤いた画⾯の差分描画を ⾏い⾼速な画⾯表⽰を提供する
  7. 7. React とは 3/3 https://facebook.github.io/react/t utorial/tutorial.html • Tutorial おすすめ • ポイント – ES2015 – React.Component – this.prop – this.state – componentXXXMount • ES2015 は以下ざっと読んでおくのが おすすめ – http://postd.cc/es6-cheatsheet/ – 「...」とか検索難易度⾼すぎる
  8. 8. React Native とは
  9. 9. React Native とは 1/3 https://facebook.github.io/react- native/ Facebook 製 • ネイティブアプリを JavaScript と React を使⽤して構築できる • ちゃんとサクサク動く本当のスマホア プリが作れる • (アプリなのに)ホットリローディン グでさくさく開発できる • Native コードも使える
  10. 10. React Native とは 2/3 https://facebook.github.io/react- native/docs/getting- started.html#content アプリ⽤のコンポネントを確認して おくと効率が良い • こちらも Getting started から Tutorial がおすすめ
  11. 11. React Native とは 3/3 http://www.slideshare.net/TadeuZagallo/a-tour- of-react-native?qid=ddc291a4-7988-46dc- b086-9cf3c92a7235&v=&b=&from_search=4 メリットとか • 今後ますますアプリの需要は⾼まって いく • Android と iPhone で 70% 〜 90% コードを共有可能 • ネイティブの勉強をゴリッとやらない で良い
  12. 12. Question
  13. 13. React Native の裏側を覗く
  14. 14. React Native の裏側を覗く https://facebook.github.io/react- native/docs/getting- started.html#content Getting Started • ⾊々インストール – node – watchman – react-native-cli – … • 初期化 • 起動 react-native init AwesomeProject react-native run-ios
  15. 15. React Native の裏側を覗く 初期化処理を react-native init からみてみる
  16. 16. React Native の裏側を覗く view `which react-native`
  17. 17. React Native の裏側を覗く switch (commands[0]) { case 'init': if (!commands[1]) { console.error( 'Usage: react-native init <ProjectName> [--verbose]' ); process.exit(1); } else { init(commands[1], argv.verbose, argv.version); } break; default: ...
  18. 18. React Native の裏側を覗く function init(name, verbose, rnPackage) { validatePackageName(name); if (fs.existsSync(name)) { createAfterConfirmation(name, verbose, rnPackage); } else { createProject(name, verbose, rnPackage); } }
  19. 19. React Native の裏側を覗く function createProject(name, verbose, rnPackage) { var root = path.resolve(name); var projectName = path.basename(root); console.log( 'This will walk you through creating a new React Native project in', root ); if (!fs.existsSync(root)) { fs.mkdirSync(root); } ・・・
  20. 20. React Native の裏側を覗く ・・・ var packageJson = { name: projectName, version: '0.0.1', private: true, scripts: { start: 'node node_modules/react-native/local-cli/cli.js start' } }; fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(packageJson)); process.chdir(root); console.log('Installing react-native package from npm...'); ・・・
  21. 21. React Native の裏側を覗く ・・・ if (verbose) { runVerbose(root, projectName, rnPackage); } else { run(root, projectName, rnPackage); } }
  22. 22. React Native の裏側を覗く function run(root, projectName, rnPackage) { exec('npm install --save --save-exact ' + getInstallPackage(rnPackage), function(e, stdout, stderr) { if (e) { console.log(stdout); console.error(stderr); console.error('`npm install --save --save-exact react-native` failed'); process.exit(1); } checkNodeVersion(); var cli = require(CLI_MODULE_PATH()); cli.init(root, projectName); }); }
  23. 23. React Native の裏側を覗く view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/cli.js
  24. 24. React Native の裏側を覗く /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ 'use strict'; require('./packager/babelRegisterOnly')([ /private-cli¥/src/ ]); module.exports = require('./local-cli/cli.js');
  25. 25. React Native の裏側を覗く view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/cli.js
  26. 26. React Native の裏側を覗く ・・・ var cliEntry = require('./cliEntry'); if (require.main === module) { cliEntry.run(); } module.exports = cliEntry;
  27. 27. たらい回し
  28. 28. React Native の裏側を覗く view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/cliEntry.js
  29. 29. React Native の裏側を覗く ・・・ const init = require('./init/init'); ・・・ module.exports = { run: run, init: init, };
  30. 30. React Native の裏側を覗く これ! function run(root, projectName, rnPackage) { exec('npm install --save --save-exact ' + getInstallPackage(rnPackage), function(e, stdout, stderr) { if (e) { console.log(stdout); console.error(stderr); console.error('`npm install --save --save-exact react-native` failed'); process.exit(1); } checkNodeVersion(); var cli = require(CLI_MODULE_PATH()); cli.init(root, projectName); }); }
  31. 31. React Native の裏側を覗く view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/init/init.js
  32. 32. React Native の裏側を覗く /** * Creates the template for a React Native project given the provided * parameters: * @param projectDir Templates will be copied here. * @param argsOrName Project name or full list of custom arguments * for the generator. */ function init(projectDir, argsOrName) { console.log('Setting up new React Native app in ' + projectDir); const args = Array.isArray(argsOrName) ? argsOrName // argsOrName was e.g. ['AwesomeApp', '--verbose'] : [argsOrName].concat(process.argv.slice(4)); // argsOrName was e.g. 'AwesomeApp’ ・・・続く
  33. 33. React Native の裏側を覗く ・・・続き // args array is e.g. ['AwesomeApp', '--verbose'] if (!args || args.length === 0) { console.error('react-native init requires a project name.'); return; } const newProjectName = args[0]; const options = minimist(args); generateProject(projectDir, newProjectName, options); }
  34. 34. React Native の裏側を覗く function generateProject(destinationRoot, newProjectName, options) { ・・・中略 copyProjectTemplateAndReplace( path.resolve('node_modules', 'react-native', 'local-cli', 'templates', 'HelloWorld'), destinationRoot, newProjectName ); ・・・中略 printRunInstructions(destinationRoot, newProjectName); }
  35. 35. React Native の裏側を覗く const copyProjectTemplateAndReplace = require('../generator/copyProjectTemplateAndReplace'); ・・・中略 require('../generator/printRunInstructions');
  36. 36. 余談
  37. 37. 余談(init.js) const yarnVersion = (!options.npm) && yarn.getYarnVersionIfAvailable() && yarn.isGlobalCliUsingYarn(destinationRoot); ・・・中略 if (yarnVersion) { console.log('Adding React...'); execSync(`yarn add react@${reactVersion}`); } else { console.log('Installing React...'); execSync(`npm install react@${reactVersion} --save --save-exact`); }
  38. 38. React Native の裏側を覗く view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/generator/copyProjectTemplateAndReplace.js
  39. 39. React Native の裏側を覗く 割愛します・・・ [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/templates/HelloWorld から [react-native init したディレクトリ]/[アプリ名] に HelloWorld を [アプリ名] に replace しながら頑張ってコピーしている処理
  40. 40. React Native の裏側を覗く $ ls -l total 64 drwxr-xr-x 4 ayumi.toukairin 386209875 136 12 10 19:23 __tests__ -rw-r--r-- 1 ayumi.toukairin 386209875 31 12 8 20:25 _babelrc -rw-r--r-- 1 ayumi.toukairin 386209875 114 12 8 20:25 _buckconfig -rw-r--r-- 1 ayumi.toukairin 386209875 1425 12 8 20:25 _flowconfig -rw-r--r-- 1 ayumi.toukairin 386209875 16 12 8 20:25 _gitattributes -rw-r--r-- 1 ayumi.toukairin 386209875 415 12 8 20:25 _gitignore -rw-r--r-- 1 ayumi.toukairin 386209875 2 12 8 20:25 _watchmanconfig drwxr-xr-x 10 ayumi.toukairin 386209875 340 12 10 19:23 android -rw-r--r-- 1 ayumi.toukairin 386209875 1106 12 8 20:25 index.android.js -rw-r--r-- 1 ayumi.toukairin 386209875 1072 12 8 20:25 index.ios.js drwxr-xr-x 5 ayumi.toukairin 386209875 170 12 10 19:23 ios
  41. 41. React Native の裏側を覗く $ ls –l total 24 drwxr-xr-x 4 ayumi.toukairin 386209875 136 12 10 19:23 __tests__ drwxr-xr-x 10 ayumi.toukairin 386209875 340 12 10 19:23 android -rw-r--r-- 1 ayumi.toukairin 386209875 1091 12 10 20:55 index.android.js -rw-r--r-- 1 ayumi.toukairin 386209875 1057 12 10 20:55 index.ios.js drwxr-xr-x 5 ayumi.toukairin 386209875 170 12 10 19:23 ios drwxr-xr-x 569 ayumi.toukairin 386209875 19346 12 10 20:55 node_modules -rw-r--r-- 1 ayumi.toukairin 386209875 421 12 10 20:55 package.json
  42. 42. React Native の裏側を覗く $ ls –l ios total 0 drwxr-xr-x 8 ayumi.toukairin 386209875 272 12 10 19:23 [アプリ名] drwxr-xr-x 4 ayumi.toukairin 386209875 136 12 10 19:23 [アプリ名].xcodeproj drwxr-xr-x 4 ayumi.toukairin 386209875 136 12 10 19:23 [アプリ名]Tests
  43. 43. というわけで
  44. 44. init 終わり!
  45. 45. Question
  46. 46. React Native の裏側を覗く 続いて react-native run-ios をみてみる
  47. 47. React Native の裏側を覗く view `which react-native`
  48. 48. React Native の裏側を覗く ・・・ var cli; var cliPath = CLI_MODULE_PATH(); if (fs.existsSync(cliPath)) { cli = require(cliPath); } // minimist api var commands = argv._; if (cli) { cli.run(); } else { ・・・
  49. 49. view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/cliEntry.js React Native の裏側を覗く
  50. 50. React Native の裏側を覗く function run() { const setupEnvScript = /^win/.test(process.platform) ? 'setup_env.bat' : 'setup_env.sh'; childProcess.execFileSync(path.join(__dirname, setupEnvScript)); const config = getCliConfig(); commands.forEach(cmd => addCommand(cmd, config)); commander.parse(process.argv); ・・・
  51. 51. view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/setup_env.sh React Native の裏側を覗く
  52. 52. React Native の裏側を覗く # Copyright (c) 2015-present, Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. # 2048 is the max for non root users on Mac ulimit -n 2048
  53. 53. React Native の裏側を覗く function run() { const setupEnvScript = /^win/.test(process.platform) ? 'setup_env.bat' : 'setup_env.sh'; childProcess.execFileSync(path.join(__dirname, setupEnvScript)); const config = getCliConfig(); commands.forEach(cmd => addCommand(cmd, config)); commander.parse(process.argv); ・・・続く
  54. 54. React Native の裏側を覗く ・・・続き const isValidCommand = commands.find(cmd => cmd.name.split(' ')[0] === process.argv[2]); if (!isValidCommand) { printUnknownCommand(process.argv[2]); return; } if (!commander.args.length) { commander.help(); } }
  55. 55. 迷⼦になった
  56. 56. React Native の裏側を覗く function run() { const setupEnvScript = /^win/.test(process.platform) ? 'setup_env.bat' : 'setup_env.sh'; childProcess.execFileSync(path.join(__dirname, setupEnvScript)); const config = getCliConfig(); commands.forEach(cmd => addCommand(cmd, config)); commander.parse(process.argv); ・・・続く ここらしい!
  57. 57. React Native の裏側を覗く const commander = require('commander'); ・・・中略 function run() { const setupEnvScript = /^win/.test(process.platform) ? 'setup_env.bat' : 'setup_env.sh'; childProcess.execFileSync(path.join(__dirname, setupEnvScript)); const config = getCliConfig(); commands.forEach(cmd => addCommand(cmd, config)); commander.parse(process.argv); ・・・ https://tj.github.io/commander.js/ ### Command#parse() Parse argv, settings options and invoking commands when defined.
  58. 58. React Native の裏側を覗く const addCommand = (command: Command, config: ConfigT) => { const options = command.options || []; const cmd = commander .command(command.name, undefined, { noHelp: !command.description, }) .description(command.description) .action(function runAction() { const passedOptions = this.opts(); const argv: Array<string> = Array.from(arguments).slice(0, -1); Promise.resolve() .then(() => { assertRequiredOptions(options, passedOptions); return command.func(argv, config, passedOptions); }) .catch(handleError); }); ・・・
  59. 59. view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/runIOS/runIOS.js React Native の裏側を覗く
  60. 60. React Native の裏側を覗く function runIOS(argv, config, args) { process.chdir(args.projectPath); const xcodeProject = findXcodeProject(fs.readdirSync('.')); if (!xcodeProject) { throw new Error('Could not find Xcode project files in ios folder'); } ・・・中略 if (args.device) { ・・・中略 } else { return runOnSimulator(xcodeProject, args, inferredSchemeName, scheme); } }
  61. 61. React Native の裏側を覗く function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ return new Promise((resolve) => { try { var simulators = JSON.parse( child_process.execFileSync('xcrun', ['simctl', 'list', '--json', 'devices'], {encoding: 'utf8'}) ); } catch (e) { throw new Error('Could not parse the simulator list output'); } const selectedSimulator = findMatchingSimulator(simulators, args.simulator); if (!selectedSimulator) { throw new Error(`Could not find ${args.simulator} simulator`); } ・・・
  62. 62. React Native の裏側を覗く Usage: xcrun [options] <tool name> ... arguments ... Find and execute the named command line tool from the active developer directory. The active developer directory can be set using `xcode-select`, or via the DEVELOPER_DIR environment variable. See the xcrun and xcode-select manualpages for more information.
  63. 63. React Native の裏側を覗く ・・・ const simulatorFullName = formattedDeviceName(selectedSimulator); console.log(`Launching ${simulatorFullName}...`); try { child_process.spawnSync('xcrun', ['instruments', '-w', selectedSimulator.udid]); } catch (e) { // instruments always fail with 255 because it expects more arguments, // but we want it to only launch the simulator } resolve(selectedSimulator.udid) }) ・・・
  64. 64. React Native の裏側を覗く ・・・ .then((udid) => buildProject(xcodeProject, udid, scheme, args.configuration)) .then((appName) => { if (!appName) { appName = inferredSchemeName; } let appPath = getBuildPath(args.configuration, appName); console.log(`Installing ${appPath}`); child_process.spawnSync('xcrun', ['simctl', 'install', 'booted', appPath], {stdio: 'inherit'}); ・・・
  65. 65. React Native の裏側を覗く ・・・ const bundleID = child_process.execFileSync( '/usr/libexec/PlistBuddy', ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')], {encoding: 'utf8'} ).trim(); console.log(`Launching ${bundleID}`); child_process.spawnSync('xcrun', ['simctl', 'launch', 'booted', bundleID], {stdio: 'inherit'}); }) }
  66. 66. view [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/packager/react-native-xcode.sh React Native の裏側を覗く
  67. 67. React Native の裏側を覗く #!/bin/bash # Copyright (c) 2015-present, Facebook, Inc. # All rights reserved. # ・・・中略 case "$CONFIGURATION" in Debug) # Speed up build times by skipping the creation of the offline package for debug # builds on the simulator since the packager is supposed to be running anyways. if [[ "$PLATFORM_NAME" == *simulator ]]; then echo "Skipping bundling for Simulator platform" exit 0; fi ・・・
  68. 68. また 迷⼦になった
  69. 69. xcodebuild -project [アプリ名].xcodeproj -configuration Debug -scheme [アプリ 名] -destination id=[udid] -derivedDataPath build React Native の裏側を覗く
  70. 70. vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/React/React.xcodeproj/project.pbxproj React Native の裏側を覗く
  71. 71. React Native の裏側を覗く #!/bin/sh if [ -z "${RCT_NO_LAUNCH_PACKAGER+xxx}" ] ; then if nc -w 5 -z localhost 8081 ; then if ! curl -s "http://localhost:8081/status" | grep -q "packager- status:running" ; then echo "Port 8081 already in use, packager is either not running or not running correctly" exit 2 fi else open "$SRCROOT/../packager/launchPackager.command" || echo "Can't start packager automatically" fi fi
  72. 72. vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/packager/launchPackager.command React Native の裏側を覗く
  73. 73. React Native の裏側を覗く #!/usr/bin/env bash # Copyright (c) 2015-present, Facebook, Inc. # All rights reserved. ・・・中略 # Set terminal title echo -en "¥033]0;React Packager¥a" clear THIS_DIR=$(dirname "$0") pushd "$THIS_DIR" source ./packager.sh popd echo "Process terminated. Press <enter> to close the window" read
  74. 74. vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/packager/packager.sh React Native の裏側を覗く
  75. 75. React Native の裏側を覗く #!/usr/bin/env bash # Copyright (c) 2015-present, Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. THIS_DIR=$(dirname "$0") node "$THIS_DIR/../local-cli/cli.js" start "$@"
  76. 76. vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/server/server.js React Native の裏側を覗く
  77. 77. React Native の裏側を覗く /** * Starts the React Native Packager Server. */ function server(argv, config, args) { ・・・中略 console.log(formatBanner( 'Running packager on port ' + args.port + '.¥n¥n' + 'Keep this packager running while developing on any JS projects. ' + 'Feel free to close this tab and run your own packager instance if you ' + 'prefer.¥n¥n' + 'https://github.com/facebook/react-native', { marginLeft: 1, marginRight: 1, paddingBottom: 1, }) ); ・・・中略 runServer(args, config, () => console.log('¥nReact packager ready.¥n')); }
  78. 78. vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react- native/local-cli/server/runServer.js React Native の裏側を覗く
  79. 79. いよいよ HotDeploy部分
  80. 80. 。。。
  81. 81. ごめんなさい。
  82. 82. まとめ
  83. 83. まとめ • React の知識を覚えるとスマホアプリが作れる、ということでそのメリットは ⼤きい • といいつつも、ハマった時のことを考えると node とアプリ構築(xcode)の 知識はある程度有ったほうが良さそう • 割と⾟かった、でも勉強になった – Simulator ⽴ち上げるまでのコードは⼤体把握できたので、ある程度トラブルシュー ティングもできるようになれば良いな・・・ • いつか続きも読みたいな
  84. 84. Question
  85. 85. Thank you

×