React Native GUIDE
-
Upload
dcubeio -
Category
Engineering
-
view
322 -
download
4
Transcript of React Native GUIDE
React Native GUIDE⼊⾨からその裏側まで覗いてみよう
About Me
ビズリーチ・キャンパス学⽣、OB/OG 向けサイト
• Java8+Spring Boot(Thymeleaf)
• ES2015+KnockoutJS
社内管理者向けサイト
• Java8+Spring Boot
• ES2015+React(+Redux)
アプリ
• Java8+Spring Boot
• Swift
React とは
React とは 1/3https://facebook.github.io/react/ Facebook 製
• UI 構築⽤の JavaScript ライブラリ
• Declarative(宣⾔的)� アプリの状態に応じたインタラクティブ
な UI を簡単に構築できる� コードもわかりやすい
• Component-Based� いわゆるコンポーネント(部品)指向
� ⾃分⾃⾝の状態も管理する
• Learn Once,Write Anywhere� これだけ覚えればサーバサイドもスマホ
アプリも OK
React とは 2/3https://speakerdeck.com/katamuki/es2015-react-dot-jswoxue-bu 弊社のおっさんが学んだ話(宣伝)
• コンポーネントを組み合わせて構築するコンポーネント指向の View ライブラリ
• Facebook、インスタ、Yahoo!、Airbnb などでも使われている
• VirtualDOMを⽤いた画⾯の差分描画を⾏い⾼速な画⾯表⽰を提供する
React とは 3/3https://facebook.github.io/react/tutorial/tutorial.html
• Tutorial おすすめ
• ポイント� ES2015� React.Component� this.prop� this.state� componentXXXMount
• ES2015 は以下ざっと読んでおくのがおすすめ� http://postd.cc/es6-cheatsheet/
� 「...」とか検索難易度⾼すぎる
React Nativeとは
React Native とは 1/3https://facebook.github.io/react-native/ Facebook 製
• ネイティブアプリを JavaScript とReact を使⽤して構築できる
• ちゃんとサクサク動く本当のスマホアプリが作れる
• (アプリなのに)ホットリローディングでさくさく開発できる
• Native コードも使える
React Native とは 2/3https://facebook.github.io/react-native/docs/getting-started.html#content
アプリ⽤のコンポネントを確認しておくと効率が良い
• こちらも Getting started からTutorial がおすすめ
React Native とは 3/3http://www.slideshare.net/TadeuZagallo/a-tour-of-react-native?qid=ddc291a4-7988-46dc-b086-9cf3c92a7235&v=&b=&from_search=4 メリットとか
• 今後ますますアプリの需要は⾼まっていく
• Android と iPhone で 70% 〜 90% コードを共有可能
• ネイティブの勉強をゴリッとやらないで良い
Question
React Nativeの裏側を覗く
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
React Nativeの裏側を覗く初期化処理を react-native init からみてみる
React Native の裏側を覗く
view `which react-native`
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:...
React Native の裏側を覗くfunction init(name, verbose, rnPackage) {validatePackageName(name);
if (fs.existsSync(name)) {createAfterConfirmation(name, verbose, rnPackage);
} else {createProject(name, verbose, rnPackage);
}}
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);
}
・・・
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...');
・・・
React Native の裏側を覗く・・・
if (verbose) {runVerbose(root, projectName, rnPackage);
} else {run(root, projectName, rnPackage);
}}
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);
});}
React Native の裏側を覗く
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/cli.js
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');
React Native の裏側を覗く
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/cli.js
React Native の裏側を覗く・・・
var cliEntry = require('./cliEntry');
if (require.main === module) {cliEntry.run();
}
module.exports = cliEntry;
たらい回し
React Native の裏側を覗く
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/cliEntry.js
React Native の裏側を覗く・・・
const init = require('./init/init');
・・・
module.exports = {run: run,init: init,
};
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);
});}
React Native の裏側を覗く
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/init/init.js
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’
・・・続く
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);}
React Native の裏側を覗くfunction generateProject(destinationRoot, newProjectName, options) {
・・・中略
copyProjectTemplateAndReplace(path.resolve('node_modules', 'react-native', 'local-cli', 'templates',
'HelloWorld'),destinationRoot,newProjectName
);
・・・中略
printRunInstructions(destinationRoot, newProjectName);}
React Native の裏側を覗くconst copyProjectTemplateAndReplace =require('../generator/copyProjectTemplateAndReplace');
・・・中略
require('../generator/printRunInstructions');
余談
余談(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`);
}
React Native の裏側を覗く
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/generator/copyProjectTemplateAndReplace.js
React Native の裏側を覗く割愛します・・・
[react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/templates/HelloWorld
から
[react-native init したディレクトリ]/[アプリ名]
に HelloWorld を [アプリ名] に replace しながら頑張ってコピーしている処理
React Native の裏側を覗く
$ ls -ltotal 64drwxr-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 _watchmanconfigdrwxr-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.jsdrwxr-xr-x 5 ayumi.toukairin 386209875 170 12 10 19:23 ios
React Native の裏側を覗く
$ ls –ltotal 24drwxr-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.jsdrwxr-xr-x 5 ayumi.toukairin 386209875 170 12 10 19:23 iosdrwxr-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
React Native の裏側を覗く
$ ls –l iostotal 0drwxr-xr-x 8 ayumi.toukairin 386209875 272 12 10 19:23 [アプリ名]drwxr-xr-x 4 ayumi.toukairin 386209875 136 12 10 19:23 [アプリ名].xcodeprojdrwxr-xr-x 4 ayumi.toukairin 386209875 136 12 10 19:23 [アプリ名]Tests
というわけで
init 終わり!
Question
React Nativeの裏側を覗く続いて react-native run-ios をみてみる
React Native の裏側を覗く
view `which react-native`
React Native の裏側を覗く・・・
var cli;var cliPath = CLI_MODULE_PATH();if (fs.existsSync(cliPath)) {cli = require(cliPath);
}
// minimist apivar commands = argv._;if (cli) {cli.run();
} else {
・・・
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/cliEntry.js
React Native の裏側を覗く
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);
・・・
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/setup_env.sh
React Native の裏側を覗く
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 Maculimit -n 2048
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);
・・・続く
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();
}}
迷⼦になった
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);
・・・続く ここらしい!
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.
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);
});・・・
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/runIOS/runIOS.js
React Native の裏側を覗く
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);
}}
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`);
}・・・
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 theDEVELOPER_DIR environment variable. See the xcrun and xcode-select manualpages formore information.
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)
})
・・・
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'});
・・・
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'});})
}
view [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/packager/react-native-xcode.sh
React Native の裏側を覗く
React Native の裏側を覗く#!/bin/bash# Copyright (c) 2015-present, Facebook, Inc.# All rights reserved.#・・・中略
case "$CONFIGURATION" inDebug)# 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 ]]; thenecho "Skipping bundling for Simulator platform"exit 0;
fi
・・・
また迷⼦になった
xcodebuild -project [アプリ名].xcodeproj -configuration Debug -scheme [アプリ名] -destination id=[udid] -derivedDataPath build
React Native の裏側を覗く
vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/React/React.xcodeproj/project.pbxproj
React Native の裏側を覗く
React Native の裏側を覗く#!/bin/shif [ -z "${RCT_NO_LAUNCH_PACKAGER+xxx}" ] ; thenif nc -w 5 -z localhost 8081 ; thenif ! curl -s "http://localhost:8081/status" | grep -q "packager-
status:running" ; thenecho "Port 8081 already in use, packager is either not running or not
running correctly"exit 2
fielseopen "$SRCROOT/../packager/launchPackager.command" || echo "Can't start
packager automatically"fi
fi
vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/packager/launchPackager.command
React Native の裏側を覗く
React Native の裏側を覗く#!/usr/bin/env bash
# Copyright (c) 2015-present, Facebook, Inc.# All rights reserved.
・・・中略
# Set terminal titleecho -en "¥033]0;React Packager¥a"clear
THIS_DIR=$(dirname "$0")pushd "$THIS_DIR"source ./packager.shpopd
echo "Process terminated. Press <enter> to close the window"read
vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/packager/packager.sh
React Native の裏側を覗く
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 "$@"
vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/server/server.js
React Native の裏側を覗く
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'));}
vim [react-native init したディレクトリ]/[アプリ名]/node_modules/react-native/local-cli/server/runServer.js
React Native の裏側を覗く
いよいよHotDeploy部分
。。。
ごめんなさい。
まとめ
まとめ• React の知識を覚えるとスマホアプリが作れる、ということでそのメリットは
⼤きい
• といいつつも、ハマった時のことを考えると node とアプリ構築(xcode)の知識はある程度有ったほうが良さそう
• 割と⾟かった、でも勉強になった� Simulator ⽴ち上げるまでのコードは⼤体把握できたので、ある程度トラブルシュー
ティングもできるようになれば良いな・・・
• いつか続きも読みたいな
Question
Thank you