Unit testing in Kotlin JS - reactjs

I have a simple project in Kotlin JavaScript using React. I've added unit tests, but when I run them, they seem to call main method of production code, and fail on initialization, when trying to reach unexsistent DOM structure. Despite the fact that the tested class does not reference React or DOM in any way.
The error looks the same when run from Intelij IDEA or by gradlew build (I've replaced the full path to my project with /APP/ for clarity):
Testing started at 17:51 ...
> Task :cleanBrowserTest
> Task :packageJson UP-TO-DATE
> Task :testPackageJson UP-TO-DATE
> Task :kotlinNodeJsSetup SKIPPED
> Task :kotlinNpmInstall
> Task :compileKotlinJs
> Task :processResources
> Task :mainClasses
> Task :compileTestKotlinJs
> Task :testProcessResources NO-SOURCE
> Task :testClasses
> Task :browserTest
(...)
Error: Target container is not a DOM element.
at render (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:25359:13)
at render_0 (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:29868:5)
at main (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146311:5)
at Object.<anonymous> (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146315:3)
at http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146289:37
at Object.../example/kotlin/example.js (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146292:2)
at __webpack_require__ (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:20:30)
at http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146346:134
at Object../kotlin/example-test.js (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:146351:2)
at __webpack_require__ (http://localhost:9876/absoluteD:/APP/build/js/packages/example-test/adapter-browser.js?92ccabfdcfa982960828b65b2f4e2683080859b4:20:30)
HeadlessChrome 81.0.4044 (Windows 10.0.0) ERROR
Uncaught Error: Target container is not a DOM element.
at d:/APP/build/js/node_modules/react-dom/cjs/react-dom.development.js:24828:1 <- D:/APP/build/js/packages/example-test/adapter-browser.js:25359:7
(...)
> Task :browserTest FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':browserTest'.
> command 'C:\Users\Arsen\.gradle\nodejs\node-v12.14.0-win-x64\node.exe' exited with errors (exit code: 1)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 10s
8 actionable tasks: 6 executed, 2 up-to-date
Minimal example:
./build.gradle.kts
plugins {
id("org.jetbrains.kotlin.js") version "1.3.70-eap-184"
}
group = "org.example"
version = "1.0-SNAPSHOT"
repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
maven("https://kotlin.bintray.com/kotlin-js-wrappers/")
mavenCentral()
jcenter()
}
dependencies {
implementation(kotlin("stdlib-js"))
implementation("org.jetbrains:kotlin-react:16.13.0-pre.94-kotlin-1.3.70")
implementation("org.jetbrains:kotlin-react-dom:16.13.0-pre.94-kotlin-1.3.70")
implementation(npm("react", "16.13.1"))
implementation(npm("react-dom", "16.13.1"))
testImplementation(kotlin("test-js"))
}
kotlin.target.browser {
}
./settings.gradle.kts
pluginManagement {
repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
mavenCentral()
maven { setUrl("https://plugins.gradle.org/m2/") }
}
}
rootProject.name = "example"
./src/main/resources/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="root"></div>
<script src="example.js"></script>
</body>
</html>
./src/main/kotlin/Main.kt
import react.dom.*
import kotlin.browser.document
fun main(args: Array<String>) {
render(document.getElementById("root")) {
}
}
./src/main/kotlin/DummyClass.kt
class DummyClass {
fun foo(): String {
return "foo"
}
}
./src/test/kotlin/ExampleTest.kt
import kotlin.test.*
class ExampleTest {
#Test
fun foo() {
assertEquals(DummyClass().foo(), "foo")
}
}
The error does not occur if I don't reference production code at all (remove DummyClass().foo() from the test), or when main method does not call render(document.getElementById("root")).
PS: If it matters I run the code on Windows

This is not the right answer - but something that will unblock you immediately.
This answer pointed out that
the test environment doesn't supply the DOM with an app id.
So too is the case with our test framework - it is not supplying an element with id 'root'.
This led me to believe that the main/resources/index.html is not being used by the test framework. The exception trace confirms that - notice how it starts from __webpack_require__
The ideal solution would be to either have karma or webpack supply our code with the correct index.html; but I don't know how to accomplish that.
In the meantime, you can
Remove <div id="root"></div> as part of index.html
Have your kotlin code generate it, as below:
./src/main/kotlin/Main.kt
fun main(args: Array<String>) {
document.body!!.insertAdjacentHTML("afterbegin", "<div id='root'></div>" )
render(document.getElementById("root")) {
}
}
Hope that helps

I had the same issue and I fixed it. Thanks to the workaround of #Yogesh Nachnani I understood what was missing. In fact all resources files are not included. So, first I created a new workaround using fs-extra (copying files from resources to the local directory) and then as I was exploring Karma I figured out that the cleanest solution was to use proxies to redirect requests to resources. Therefore I used the following code into karma.config.js:
const path = require('path');
const resourcesSourcePath = path.resolve(__dirname, '../../../../build/processedResources/js/main');
const setupFile = path.resolve(__dirname, '../../../../src/test/setup.js');
config.files.unshift(setupFile);
config.proxies = {
"/strings/": "absolute" + resourcesSourcePath + "/strings/",
"/css/": "absolute" + resourcesSourcePath + "/css/",
"/images/": "absolute" + resourcesSourcePath + "/images/"
}
This way, if you have a lot of resources you won't have to wait for the copy of the content. However, I didn't find a way to launch karma on index.html, but as I can now access all resources, I just used the workaround proposed by #Yogesh Nachnani because the HTML file usually doesn't have much influence into tests (at least for me). Therefore I added a setup.js file which only contains:
document.body.insertAdjacentHTML('afterbegin', "<div id='root'></div>");
It prevents the rendering target error when you are using render(document.getElementById("root")){} for React.

Related

kotlin(multiplatform) version 1.7.20 incompatibility with spring-boot and kotlin/js react

I am trying to create a kotlin multiplatform project with spring-boot and kotlin/js react
This is the build.gradle.kts am using:
plugins {
id("org.springframework.boot") version "2.7.4" apply false
id("io.spring.dependency-management") version "1.0.14.RELEASE" apply false
kotlin("multiplatform") version "1.7.20"
kotlin("plugin.spring") version "1.7.20" apply false
}
group = "com.examples"
version = "1.0-SNAPSHOT"
repositories {
jcenter()
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")
}
kotlin {
jvm {
apply(plugin = "org.springframework.boot")
apply(plugin = "io.spring.dependency-management")
apply(plugin = "org.jetbrains.kotlin.plugin.spring")
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
withJava()
}
js(IR) {
binaries.executable()
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
sourceSets {
val commonMain by getting
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val jvmMain by getting {
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
}
}
val jvmTest by getting {
dependencies {
implementation("org.springframework.boot:spring-boot-starter-test")
}
}
val jsMain by getting {
dependencies {
implementation("org.jetbrains.kotlin-wrappers:kotlin-react:18.2.0-pre.346")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom:18.2.0-pre.346")
implementation("org.jetbrains.kotlin-wrappers:kotlin-emotion:11.9.3-pre.346")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-router-dom:6.3.0-pre.346")
implementation("org.jetbrains.kotlin-wrappers:kotlin-redux:4.1.2-pre.346")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-redux:7.2.6-pre.346")
}
}
val jsTest by getting
}
}
tasks.named<Copy>("jvmProcessResources") {
val jsBrowserDistribution = tasks.named("jsBrowserDistribution")
from(jsBrowserDistribution)
}
However, ./gradlew build throws this
./gradlew clean build
> Configure project :
Kotlin Multiplatform Projects are an Alpha feature. See: https://kotlinlang.org/docs/reference/evolution/components-stability.html. To hide this message, add
'kotlin.mpp.stability.nowarn=true' to the Gradle properties.
The property 'kotlin.mpp.enableGranularSourceSetsMetadata=true' has no effect in this and future Kotlin versions, as Hierarchical Structures support is now en
abled by default. It is safe to remove the property.
The property 'kotlin.native.enableDependencyPropagation=false' has no effect in this and future Kotlin versions, as Kotlin/Native dependency commonization is
now enabled by default. It is safe to remove the property.
> Task :compileKotlinJvm FAILED
e: java.lang.NoSuchMethodError: 'void kotlin.script.experimental.api.KotlinType.<init>(kotlin.reflect.KClass, boolean, int, kotlin.jvm.internal.DefaultConstru
ctorMarker)'
at org.jetbrains.kotlin.scripting.definitions.ScriptCompilationConfigurationFromDefinition$1.invoke(ScriptCompilationConfigurationFromDefinition.kt:32
)
at org.jetbrains.kotlin.scripting.definitions.ScriptCompilationConfigurationFromDefinition$1.invoke(ScriptCompilationConfigurationFromDefinition.kt:28
)
at kotlin.script.experimental.api.ScriptCompilationConfiguration.<init>(scriptCompilation.kt:23)
at kotlin.script.experimental.api.ScriptCompilationConfiguration.<init>(scriptCompilation.kt:25)
at org.jetbrains.kotlin.scripting.definitions.ScriptCompilationConfigurationFromDefinition.<init>(ScriptCompilationConfigurationFromDefinition.kt:27)
at org.jetbrains.kotlin.scripting.definitions.ScriptDefinition$Companion.getDefault(ScriptDefinition.kt:221)
at org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationExtension.updateConfiguration(ScriptingCompilerConfigurationExtension.
kt:67)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.configureProjectEnvironment(KotlinCoreEnvironment.kt:578)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment.<init>(KotlinCoreEnvironment.kt:199)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment.<init>(KotlinCoreEnvironment.kt:108)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.createForProduction(KotlinCoreEnvironment.kt:445)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.createCoreEnvironment(K2JVMCompiler.kt:192)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:143)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:53)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:99)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:47)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:475)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:125)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:373)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally$default(IncrementalCompilerRunner.kt:318)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.rebuild(IncrementalCompilerRunner.kt:114)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:207)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:79)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:625)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:101)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1746)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
FAILURE: Build completed with 2 failures.
1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':compileKotlinJvm'.
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction
> Internal compiler error. See log for more details
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
==============================================================================
2: Task failed with an exception.
-----------
* What went wrong:
java.lang.StackOverflowError (no error message)
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
==============================================================================
* Get more help at https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.5.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD FAILED in 5s
9 actionable tasks: 7 executed, 2 up-to-date
How to fix this?
Note that if I use version 1.6.21 (as suggested by https://start.spring.io/) for kotlin multiplatorm and kotlin spring plugin, then compiler is unable to resolve imports related to kotlin/js react
import kotlinx.browser.document
import react.create
import react.dom.client.createRoot

workerize-loader failed to work after compiling (react typescript)

I created a rust-wasm module and use workerize-loader to load it:
export const getQRCode = async (
arg: string,
width: number,
height: number
) => {
const { qrcode } = await import('uranus-qrcode');
return qrcode(arg, width, height);
};
and then I use the worker as such:
// #ts-ignore
// eslint-disable-next-line import/no-webpack-loader-syntax
import qrCodeWorker from 'workerize-loader!workers/qrCodeWorker';
...
const workerizeQRLoader = async () => {
try {
const instance = qrCodeWorker();
const qr = await instance.getQRCode(href, 150, 150);
setQRCode({
__html: qr
});
} catch (e) {
console.warn(e);
}
};
...
useEffect(() => {
workerizeQRLoader();
// qrLoader();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
...
The above works in dev mode, but after compiling it says:
TypeError: a.getQRCode is not a function
at 8.a2ac9b2e.chunk.js:1
at l (0.69608c56.chunk.js:2)
at Generator._invoke (0.69608c56.chunk.js:2)
at Generator.forEach.e.<computed> [as next] (0.69608c56.chunk.js:2)
at r (0.69608c56.chunk.js:2)
at s (0.69608c56.chunk.js:2)
at 0.69608c56.chunk.js:2
at new Promise (<anonymous>)
at 0.69608c56.chunk.js:2
at 8.a2ac9b2e.chunk.js:1
If I import the rust-wasm module directly into the main thread it works:
...
const qrLoader = async () => {
const { qrcode: render } = await import('uranus-qrcode');
const qr = await render(href, 150, 150);
setQRCode({
__html: qr
});
};
useEffect(() => {
// workerizeQRLoader();
qrLoader();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
...
Basically I try to get React (Webpack & TypeScript flavor) to load WebAssembly modules (aka wasm, created via Rust-Wasmbindgen) through web workers. I've tried workerize-loader + wasm-loader, and it works pretty well in the dev mode but once it is compiled, the prototype will not be added to the worker (suspecting it's a bug in workerize-loader because all workerized modules behave the same). I also tried to work with worker-loader + comlink, but the worker-loader doesn't seem to work with wasm-loader (would not be able to import wasm into the worker). The only way to get this to work is to load wasm into the main thread via wasm-loader and just give up the multi-threads setup which is basically a shame...so does anyone have successfully use a WebAssembly module loaded through a web worker in a React TypeScript project? What's your setup?
I also created a starter project: https://github.com/aeroxy/react-typescript-webassembly-starter.git
You can checkout the "workerize" branch and see how it works in dev mode but after compiling, it throws "not a function" error.
This is a bit much for a comment but I got some bad and good news. Executed the following commands using node v12.16.1 and yarn 1.22.4:
git clone https://github.com/aeroxy/react-typescript-webassembly-starter.git
cd react-typescript-webassembly-starter
yarn # some warnings that packages need to be updated to later version
yarn start # dev version works
yarn build
cd build
npx serve
When opening the build version in Google Chrome 81.0.4044.113 (Official Build) (64-bit) on my Fedora 31 I can see the qr code, no errors in console.
That means that there is no fault in the project (good news) but something maybe wrong in settings on your machine (bad news), the os you are using or some other machine specific difference.
You could try a to clone the project again and run the commands exactly like I did to see if that's working. Older npm could have some problems with cached packages but that's been fixed for a while now. A while ago you needed to change the repository for npm or use vpn because it was blocked, this could also be causing you trouble.
This is a duplicate of my original answer but got deleted for some odd reason by a moderator without leaving a reason.
Now the workerize method works!
I've originally tried workerize-loader + wasm-loader, and it works pretty well in the dev mode but once it is compiled, the prototype will not be added to the worker (suspecting it's a bug in workerize-loader because all workerized modules behave the same). This indeed turns out to be a bug in workerize-loader (see workerize-loader failed to work after compiling and Version 1.2.0 does not export function on worker instance in production mode). After upgrading to the workerize-loader 1.2.1, it works in both dev and prod code.
I have updated the Master repo: https://github.com/aeroxy/react-typescript-webassembly-starter.git

Gulp - throw er; // Unhandled 'error' event

gulp-htmlmin throwing err like
events.js:183
throw er; // Unhandled 'error' event
^
Error: Parse Error: <!-- END PAGE CONTENT WRAPPER
This same code work with other project but when I'm running gulp it is throwing error like this. How can I resove this.
here, my gulp file code
let gulp = require('gulp');
let htmlmin = require('gulp-htmlmin');
//Pages
gulp.task('pages', function () {
gulp.src(['./src/**/*html'])
.pipe(htmlmin({
collapseWhitespace: true,
removeComments: true
}))
.pipe(gulp.dest('./public'));
});
gulp.task('default', ['pages']);
Can anyone help?
Thanks in advance.
If the code is working on other machines it’s usually either:
One of the gulp dependencies doesn’t work with your version of node. Type node -v into your terminal and compare that with your coworkers. I’d recommend the LTS version of node as it’s the most stable
Somewhere down the line your node_modules became corrupt. Try deleting the entire node_modules directory and run npm install
Thank you all for comments and answer.
I got the solution. I've re-install all node modules (as per Joe Rushton's suggestion) and add gulp-util module to track error. I've found <!-- END PAGE CONTENT WRAPPER is unfinished comment in HTML file, it should be like <!-- END PAGE CONTENT WRAPPER -->.

How to use the variable from a <script></script> after adding it?

http://cloudinary.com/blog/how_to_build_an_image_library_with_react_cloudinary
(except I used create-react-app instead of manually configuring webpack)
Where the script is added to of index.html:
<script src="//widget.cloudinary.com/global/all.js" type="text/javascript"></script>
and then the functionality is included in a component:
uploadWidget() {
cloudinary.openUploadWidget({ cloud_name: 'CLOUD_NAME', upload_preset: 'PRESET', tags:['xmas']},
function(error, result) {
console.log(result);
});
}
However I am getting the error: 'cloudinary' is not defined
Is cloudinary supposed to be available there after simply adding the script? Am I missing a step?
Try to access it through window.cloudinary. Also make sure that the script is included before your React script is included.

React-router issues using static-render-webpack-plugin

I just started working with React last week, and I'm having trouble following a tutorial for the static-render-webpack-plugin.
I've put the code online at GitHub if you want to take a closer look.
After following the tutorial and making a couple of changes (I added babel-core, I changed the js loader to babel-loader and the entry point url needed a small correction), when I try to run webpack -p to generate the static files I get the following error:
ERROR in ./src/entry.js
Module build failed: SyntaxError: .../src/entry.js: Unexpected token (10:2)
8 |
9 | const routes = (
> 10 | <Route path="/" handler={RootPage}>
| ^
I think it might have something to do with the changes made with the latest version of react-router. I'm using the latest version, but the syntax for the tutorial looks like it might have been written prior to v.1.0. For example, I think the part of the tutorial that says to add this to the src/entry.js file:
if (typeof document != 'undefined') {
Router.run(routes, path, (Root) => {
React.render(<Root/>, document);
});
}
probably needs to be rewritten to something like this (but I'm not sure if this is quite right):
if (typeof document != 'undefined') {
ReactDOM.render(routes, document);
}
There's obviously more going on though since I get the same error message when I try that rewritten snippet then run webpack-dev-server -- which is the only time it should hit that code. (Yes, I added import ReactDOM from 'react-dom'; to the top of the page and "react-dom": "^0.14.7", to the package.json.)
I am sure this part (also on src/entry.js) needs to be rewritten to match the latest react-router too but I'm not sure how:
export default function(path, props, callback) {
Router.run(routes, path, (Root) => {
const html = React.renderToString(<Root/>);
callback('<!doctype html>' + html);
});
}
Thanks in advance for any help or hints you can give.
Your code is breaking because Webpack doesn't know how to transpile the JSX to ES5. You've specified babel-loader as your loader for JS files in your webpack config, but unfortunately Babel 6 does not do anything out of the box, you need to include "plugins" that contain the rules for compiling different syntaxes down to ES5. In this case, you'll want the es2015 preset to support all ES6 syntax, and the react preset to support JSX. You're also missing the extract-text-webpack-plugin you are trying to import into your webpack config. Snag these through NPM:
npm i -D babel-preset-2015 babel-preset-react extract-text-webpack-plugin
Then, add the presets to your webpack.config.js file in the loaders section for js/jsx files:
{
test: /\.(js|jsx)?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
I forked your repo and made these changes and was able to get a bit further through the compilation process. It seems like there are module dependencies specific to your project you'll still need to resolve.

Resources