Merge pull request #140 from drapanjanas/auto-require
Auto-require: infer components in use-figwheel command
This commit is contained in:
commit
45712a7627
20
README.md
20
README.md
|
@ -224,12 +224,28 @@ And you want to use a component called 'some-library/Component':
|
||||||
```clojure
|
```clojure
|
||||||
(def Component (js/require "some-library/Component"))
|
(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
|
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
|
code to be available at runtime. But, dynamically loaded (by Figwheel) code bypasses this scan
|
||||||
and therefore requiring the custom component fails.
|
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
|
$ re-natal use-component some-library/Component
|
||||||
```
|
```
|
||||||
|
|
|
@ -33,6 +33,8 @@ ipAddressRx = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/i
|
||||||
figwheelUrlRx = /ws:\/\/[0-9a-zA-Z\.]*:/g
|
figwheelUrlRx = /ws:\/\/[0-9a-zA-Z\.]*:/g
|
||||||
appDelegateRx = /http:\/\/[^:]+/g
|
appDelegateRx = /http:\/\/[^:]+/g
|
||||||
debugHostRx = /host]\s+\?:\s+@".*";/g
|
debugHostRx = /host]\s+\?:\s+@".*";/g
|
||||||
|
namespaceRx = /\(ns\s+([A-Za-z0-9.-]+)/g
|
||||||
|
jsRequireRx = /js\/require "(.+)"/g
|
||||||
rnVersion = '0.47.1'
|
rnVersion = '0.47.1'
|
||||||
rnWinVersion = '0.47.0-rc.5'
|
rnWinVersion = '0.47.0-rc.5'
|
||||||
rnPackagerPort = 8081
|
rnPackagerPort = 8081
|
||||||
|
@ -210,6 +212,7 @@ generateConfig = (interfaceName, projName) ->
|
||||||
modules: []
|
modules: []
|
||||||
imageDirs: ["images"]
|
imageDirs: ["images"]
|
||||||
platforms: {}
|
platforms: {}
|
||||||
|
autoRequire: true
|
||||||
|
|
||||||
for platform in platforms
|
for platform in platforms
|
||||||
config.platforms[platform] =
|
config.platforms[platform] =
|
||||||
|
@ -680,13 +683,52 @@ updateIosRCTWebSocketExecutor = (iosHost) ->
|
||||||
RCTWebSocketExecutorPath = "node_modules/react-native/Libraries/WebSocket/RCTWebSocketExecutor.m"
|
RCTWebSocketExecutorPath = "node_modules/react-native/Libraries/WebSocket/RCTWebSocketExecutor.m"
|
||||||
edit RCTWebSocketExecutorPath, [[debugHostRx, "host] ?: @\"#{iosHost}\";"]]
|
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) ->
|
platformModulesAndImages = (config, platform) ->
|
||||||
images = scanImages(config.imageDirs).map (fname) -> './' + fname;
|
if config.autoRequire? and config.autoRequire
|
||||||
modulesAndImages = config.modules.concat images;
|
requires = buildRequireByPlatformMap()
|
||||||
if typeof config.platforms[platform].modules is 'undefined'
|
requires.common.concat(requires[platform])
|
||||||
modulesAndImages
|
|
||||||
else
|
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 = () ->
|
generateDevScripts = () ->
|
||||||
try
|
try
|
||||||
|
@ -705,6 +747,9 @@ generateDevScripts = () ->
|
||||||
for platform in platforms
|
for platform in platforms
|
||||||
devHost[platform] = config.platforms[platform].host
|
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
|
for platform in platforms
|
||||||
moduleMap = generateRequireModulesCode(platformModulesAndImages(config, platform))
|
moduleMap = generateRequireModulesCode(platformModulesAndImages(config, platform))
|
||||||
fs.writeFileSync "index.#{platform}.js", "#{moduleMap}require('figwheel-bridge').withModules(modules).start('#{projName}','#{platform}','#{devHost[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
|
logErr message
|
||||||
|
|
||||||
inferComponents = () ->
|
inferComponents = () ->
|
||||||
onlyUserCljs = (item) -> fpath.extname(item.path) == '.cljs' and
|
requiresByPlatform = buildRequireByPlatformMap()
|
||||||
item.path.indexOf('/target/') < 0 # ignore target dir
|
|
||||||
jsRequire = /js\/require \"(.+)\"/g
|
allRequires = []
|
||||||
files = klawSync process.cwd(),
|
for k,v of requiresByPlatform
|
||||||
nodir: true
|
allRequires = Array.from(new Set(allRequires.concat(v)))
|
||||||
filter: onlyUserCljs
|
|
||||||
filenames = files.map((o) -> o.path)
|
|
||||||
contents = filenames.map((path) -> fs.readFileSync(path, encoding: 'utf8'))
|
|
||||||
|
|
||||||
config = readConfig() # re-natal file
|
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)
|
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)
|
if(difference.size isnt 0)
|
||||||
log "new component import found #{Array.from(difference)}"
|
log "new component import found #{Array.from(difference)}"
|
||||||
config.modules = Array.from(requires)
|
config.modules = Array.from(allRequires)
|
||||||
writeConfig(config)
|
writeConfig(config)
|
||||||
else
|
else
|
||||||
log "no new component was imported, defaulting to #{Array.from(modules)}"
|
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._name = 're-natal'
|
||||||
cli.version pkgJson.version
|
cli.version pkgJson.version
|
||||||
|
|
||||||
|
@ -902,6 +948,16 @@ cli.command 'enable-source-maps'
|
||||||
.action () ->
|
.action () ->
|
||||||
patchReactNativePackager()
|
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'
|
cli.command 'copy-figwheel-bridge'
|
||||||
.description 'copy figwheel-bridge.js into project'
|
.description 'copy figwheel-bridge.js into project'
|
||||||
.action () ->
|
.action () ->
|
||||||
|
|
Loading…
Reference in New Issue