diff --git a/README.md b/README.md index a53d0a8..e2258a8 100644 --- a/README.md +++ b/README.md @@ -224,12 +224,28 @@ And you want to use a component called 'some-library/Component': ```clojure (def Component (js/require "some-library/Component")) ``` -This would work when you do `lein prod-build` and run your app, but will fail when you run with Figwheel. +This works fine when you do `lein prod-build` and run your app. + The React Native packager statically scans for all calls to `require` and prepares the required code to be available at runtime. But, dynamically loaded (by Figwheel) code bypasses this scan and therefore requiring the custom component fails. -To overcome this run `use-component`: +In re-natal this is solved by adding all dependencies in index.*.js file which is scanned by React Native packager. + +#### Using auto-require + +To enable auto-require feature you have to run command: +``` +$ re-natal enable-auto-require +``` +From now on, command `use-figwheel` will scan for all required modules and generate index.*.js with all required dependencies. +You will have to re-run `use-figwheel` command every time you use new modules via `(js/require "...")` + +This feature is available since re-natal@0.7.0 + +#### Manually registering dependencies with use-component command + +You can register a single dependency manually by running `use-component` command: ``` $ re-natal use-component some-library/Component ``` diff --git a/re-natal.coffee b/re-natal.coffee index 693e97a..15ba9ce 100644 --- a/re-natal.coffee +++ b/re-natal.coffee @@ -33,6 +33,8 @@ ipAddressRx = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/i figwheelUrlRx = /ws:\/\/[0-9a-zA-Z\.]*:/g appDelegateRx = /http:\/\/[^:]+/g debugHostRx = /host]\s+\?:\s+@".*";/g +namespaceRx = /\(ns\s+([A-Za-z0-9.-]+)/g +jsRequireRx = /js\/require "(.+)"/g rnVersion = '0.47.1' rnWinVersion = '0.47.0-rc.5' rnPackagerPort = 8081 @@ -210,6 +212,7 @@ generateConfig = (interfaceName, projName) -> modules: [] imageDirs: ["images"] platforms: {} + autoRequire: true for platform in platforms config.platforms[platform] = @@ -680,13 +683,52 @@ updateIosRCTWebSocketExecutor = (iosHost) -> RCTWebSocketExecutorPath = "node_modules/react-native/Libraries/WebSocket/RCTWebSocketExecutor.m" edit RCTWebSocketExecutorPath, [[debugHostRx, "host] ?: @\"#{iosHost}\";"]] +platformOfNamespace = (ns) -> + if ns? + possiblePlatforms = Object.keys platformMeta + p = possiblePlatforms.find((p) -> ns.indexOf(".#{p}") > 0); + p ?= "common" + +extractRequiresFromSourceFile = (file) -> + content = fs.readFileSync(file, encoding: 'utf8') + requires = [] + while match = namespaceRx.exec(content) + ns = match[1] + while match = jsRequireRx.exec(content) + requires.push(match[1]) + + platform: platformOfNamespace(ns) + requires: requires + +buildRequireByPlatformMap = () -> + onlyUserCljs = (item) -> fpath.extname(item.path) == '.cljs' and + item.path.indexOf('/target/') < 0 # ignore target dir + files = klawSync process.cwd(), + nodir: true + filter: onlyUserCljs + filenames = files.map((o) -> o.path) + extractedRequires = filenames.map(extractRequiresFromSourceFile) + + extractedRequires.reduce((result, item) -> + platform = item.platform + if result[platform]? + result[platform] = Array.from(new Set(item.requires.concat(result[platform]))) + else + result[platform] = Array.from(new Set(item.requires)) + result + , {}) + platformModulesAndImages = (config, platform) -> - images = scanImages(config.imageDirs).map (fname) -> './' + fname; - modulesAndImages = config.modules.concat images; - if typeof config.platforms[platform].modules is 'undefined' - modulesAndImages + if config.autoRequire? and config.autoRequire + requires = buildRequireByPlatformMap() + requires.common.concat(requires[platform]) else - modulesAndImages.concat(config.platforms[platform].modules) + images = scanImages(config.imageDirs).map (fname) -> './' + fname; + modulesAndImages = config.modules.concat images; + if typeof config.platforms[platform].modules is 'undefined' + modulesAndImages + else + modulesAndImages.concat(config.platforms[platform].modules) generateDevScripts = () -> try @@ -705,6 +747,9 @@ generateDevScripts = () -> for platform in platforms devHost[platform] = config.platforms[platform].host + if config.autoRequire? and config.autoRequire + log 'Auto-require is enabled. Scanning for require() calls in *.cljs files...' + for platform in platforms moduleMap = generateRequireModulesCode(platformModulesAndImages(config, platform)) fs.writeFileSync "index.#{platform}.js", "#{moduleMap}require('figwheel-bridge').withModules(modules).start('#{projName}','#{platform}','#{devHost[platform]}');" @@ -801,30 +846,31 @@ useComponent = (name, platform) -> logErr message inferComponents = () -> - onlyUserCljs = (item) -> fpath.extname(item.path) == '.cljs' and - item.path.indexOf('/target/') < 0 # ignore target dir - jsRequire = /js\/require \"(.+)\"/g - files = klawSync process.cwd(), - nodir: true - filter: onlyUserCljs - filenames = files.map((o) -> o.path) - contents = filenames.map((path) -> fs.readFileSync(path, encoding: 'utf8')) + requiresByPlatform = buildRequireByPlatformMap() + + allRequires = [] + for k,v of requiresByPlatform + allRequires = Array.from(new Set(allRequires.concat(v))) config = readConfig() # re-natal file - requires = new Set() - contents.forEach((text) -> - while match = jsRequire.exec(text) - requires.add(match[1]) if match[1].indexOf(config.imageDirs) < 0) - modules = new Set(config.modules) - difference = new Set(Array.from(requires).filter((m) -> !modules.has(m))) + difference = new Set(Array.from(allRequires).filter((m) -> !modules.has(m))) if(difference.size isnt 0) log "new component import found #{Array.from(difference)}" - config.modules = Array.from(requires) + config.modules = Array.from(allRequires) writeConfig(config) else log "no new component was imported, defaulting to #{Array.from(modules)}" +autoRequire = (enabled) -> + config = readConfig() + config.autoRequire = enabled + writeConfig(config) + if (enabled) + log "Auto-Require feature is enabled in use-figwheel command" + else + log "Auto-Require feature is disabled in use-figwheel command" + cli._name = 're-natal' cli.version pkgJson.version @@ -902,6 +948,16 @@ cli.command 'enable-source-maps' .action () -> patchReactNativePackager() +cli.command 'enable-auto-require' + .description 'enables source scanning for automatic required module resolution in use-figwheel command.' + .action () -> + autoRequire(true) + +cli.command 'disable-auto-require' + .description 'disables auto-require feature in use-figwheel command' + .action () -> + autoRequire(false) + cli.command 'copy-figwheel-bridge' .description 'copy figwheel-bridge.js into project' .action () ->