diff --git a/.eslintrc b/.eslintrc index 44a504e4..b642bbc5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -7,7 +7,7 @@ "es6": true }, "parserOptions": { - "ecmaVersion": 6 + "ecmaVersion": 2018 }, "rules": { "no-console": "off", diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..dc82ae54 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: +- package-ecosystem: npm + directory: "/" + schedule: + interval: daily + time: "10:00" + open-pull-requests-limit: 10 + versioning-strategy: increase diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index a48d7ba2..fc65f555 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,28 +1,11 @@ - - - - - - - - - - + + - - + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index a55e7a17..6e6eec11 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/.idea/create-react-kotlin-app.iml b/.idea/create-react-kotlin-app.iml index c6e12956..c2c77f9f 100644 --- a/.idea/create-react-kotlin-app.iml +++ b/.idea/create-react-kotlin-app.iml @@ -3,10 +3,10 @@ - - - - + + + + diff --git a/.nvmrc b/.nvmrc index 45a4fb75..ca4a60d1 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -8 +v14.18.2 diff --git a/.yarnrc b/.yarnrc index 9de2b7ed..9308045b 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1 +1,2 @@ --no-lockfile true + diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29b..ee1e4349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,42 @@ +# 06.11.2018 + +kotlin-webpack-plugin@2.0.1, react-scripts-kotlin@3.0.1 + +* Minor fixes + +# 02.11.2018 + +kotlin-webpack-plugin@2.0.0, react-scripts-kotlin@3.0.0 + +* **BREAKING CHANGE** Webpack 4 +* **BREAKING CHANGE** Dropped support for Node versions earlier than 8.6 + +# 30.10.2018 + +create-react-kotlin-app@1.0.11, kotlin-webpack-plugin@1.2.11, kotlinc-js-api@1.2.11, react-scripts-kotlin@2.1.15 + +* Kotlin 1.3.0 +* React 16.6.0 +* @jetbrains/kotlin-* packages updated to pre.58 + +# 26.09.2018 + +kotlin-webpack-plugin@1.2.10, kotlinc-js-api@1.2.10, react-scripts-kotlin@2.1.14 + +* Minor fixes + +# 13.09.2018 + +create-react-kotlin-app@1.0.10, gen-idea-libs@1.0.11, kotlin-webpack-plugin@1.2.9, kotlinc-js-api@1.2.9, react-scripts-kotlin@2.1.12 + +* React 16.5.0 +* @jetbrains/kotlin-* packages updated to pre.53 +* Added an explicit dependency on core-js + +# 22.08.2018 + +create-react-kotlin-app@1.0.9, kotlin-webpack-plugin@1.2.8, kotlinc-js-api@1.2.8, react-scripts-kotlin@2.1.12, ts2kt-automator@1.0.12 + +* Kotlin 1.2.61 +* React 16.4.2 +* @jetbrains/kotlin-* packages updated to pre.49 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..9f76975c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,34 @@ +# Code of Conduct + +This code of conduct outlines our expectations for all those who participate in our open source projects and communities (community programs), as well as the consequences for unacceptable behaviour. We invite all those who participate to help us create safe and positive experiences for everyone. Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society. + +## How to behave +The following behaviours are expected and requested of all community members: + +* Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community. +* Exercise consideration, respect and empathy in your speech and actions. Remember, we have all been through different stages of learning when adopting technologies. +* Refrain from demeaning, discriminatory, or harassing behaviour and speech. +* Disagreements on things are fine, argumentative behaviour or trolling are not. + +## How not to behave + +* Do not perform threats of violence or use violent language directed against another person. +* Do not make jokes of sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory nature, or use language of this nature. +* Do not post or display sexually explicit or violent material. +* Do not post or threaten to post other people’s personally identifying information ("doxing"). +* Do not make personal insults, particularly those related to gender, sexual orientation, race, religion, or disability. +* Do not engage in sexual attention. This includes, sexualised comments or jokes and sexual advances. +* Do not advocate for, or encourage, any of the above behaviour. + +Please take into account that online communities bring together people from many different cultures and backgrounds. It's important to understand that sometimes the combination of cultural differences and online interaction can lead to misunderstandings. That is why having empathy is very important. + +## How to report issues + +If someone is acting inappropriately or violating this Code of Conduct in any shape or form, and they are not receptive to your feedback or you prefer not to confront them, please reach out to JetBrains via codeofconduct@jetbrains.com + +## Consequences of Unacceptable Behaviour + +Unacceptable behaviour from any community member will not be tolerated. Anyone asked to stop unacceptable behaviour is expected to comply immediately. If a community member engages in unacceptable behaviour, JetBrains and/or community organisers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning. + +### License and attribution +The license is based off of The Citizen Code of Conduct is distributed by Stumptown Syndicate under a Creative Commons Attribution-ShareAlike license. diff --git a/README-ja.md b/README-ja.md new file mode 100644 index 00000000..5ab6a09e --- /dev/null +++ b/README-ja.md @@ -0,0 +1,195 @@ +[![Build Status](https://teamcity.jetbrains.com/app/rest/builds/buildType:JetBrainsUi_CreateReactKotlinApp/statusIcon.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=JetBrainsUi_CreateReactKotlinApp&guest=1) +[![JetBrains team project](http://jb.gg/badges/team.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) + +[English](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README.md) +[Korean](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-ko.md) + +# Create React Kotlin App + +ビルド構成をせずに [React](https://facebook.github.io/react/) のアプリを [Kotlin](https://kotlinlang.org/) でコーディングすることができます。 + +これは **初期プレビュー版** です。 + +## 概要 + +**先に進む前に [JDK 8](http://www.oracle.com/technetwork/java/index.html) がインストールされていることを確認してください。** Java 9 以降はまだサポートされていません. + +プロジェクトの作成: + +```sh +npx create-react-kotlin-app my-app +``` + +([npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) にはnpm 5.2以降が付属しています。より古いnpmバージョンについては[インストール](#インストール)を参照してください。) + +プロジェクトを動かす: + +```sh +cd my-app/ +npm start +``` + +次に [http://localhost:3000/](http://localhost:3000/) を開いてアプリを動作させます + +実際にビルドする準備が整ったら `npm run build` を使用して縮小バンドルを作成します。 + +Create React Kotlin App を使用するだけで、Kotlin,WebPack,IntelliJ IDEAの構成が行われます。それにより、あなたはコードを書くことだけに集中することができます。 + +プロジェクトを作成するだけで、全てが上手くいくでしょう。 + +## 入門 + +### インストール + +最初にグローバルにインストールします: + +```sh +npm install -g create-react-kotlin-app +``` + +`create-react-app` がすでにインストールされているか、もしくは `npx` を利用している場合、この手順はステップでキます。 + +**Node6以上が必要です**。 [nvm](https://github.com/creationix/nvm#usage) を使用すれば、プロジェクトごとに簡単にNodeバージョンを切り替えることができます。 + +**このツールはサーバーサイドNode.jsを想定していません**。 Nodeのインストールは、Create React Kotlin Appを動かすためにのみ必要です。 + +### KotlinでReactを使う + +React上でKotlinでアプリケーションを開発するには、 [React用のKotlinラッパー](https://www.npmjs.com/package/@jetbrains/kotlin-react) が必要です。 +それのドキュメントと使用例は [モジュールのリポジトリ](https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-react)にあります。 + +### Kotlin/JS パッケージを追加する + +Create React Kotlin App をベースにしたパッケージを追加するための **設定は必要ありません**。私達は開発者のためにこのことを重要視しています。 + [https://www.npmjs.com/package/kotlinx-coroutines-core](coroutines) サポートを追加するためには `npm install kotlinx-coroutines-core` を実行するか、 [React Router DOMのラッパー](https://www.npmjs.com/package/@jetbrains/kotlin-react-router-dom) を入れるために `npm install @jetbrains/kotlin-react-router-dom` を実行してください。 + +### アプリを作る + +新しいアプリを作るためには、次のコマンドを実行してください: + +```sh +create-react-kotlin-app my-app +cd my-app +``` + +または `create-react-app` がすでにインストールされている場合は、次のコマンドを実行することができます: + +```sh +create-react-app my-app --scripts-version react-scripts-kotlin +cd my-app +``` + +このコマンドは、現在のフォルダ内にmy-appというフォルダを生成します + +このプロジェクトは、[IntelliJ IDEA](https://www.jetbrains.com/idea/) ですぐに開発できるように事前に設定されています。 もし、intelliJ IDEAの.ideaフォルダを作成したくないのであれば、`--no-idea` オプションをつけてください。 + +初期のプロジェクト構造が作成され、依存関係がインストールされます: + +``` +my-app/ + README.md + node_modules/ + package.json + .gitignore + public/ + favicon.ico + index.html + manifest.json + src/ + app/ + App.css + App.kt + index/ + index.css + index.kt + logo/ + kotlin.svg + Logo.css + Logo.kt + react.svg + ticker/ + Ticker.kt +``` + +アプリを開いてから経過した時間を表示する簡単なアプリです。 +インストールが完了したら、プロジェクトフォルダ内でいくつかのコマンドを実行できます: + +### `npm start` または `yarn start` + +開発モードでアプリを起動します。 +ブラウザ上で表示するためには [http://localhost:3000](http://localhost:3000) にアクセスします。 + +ページを編集すると、自動的にページが更新されます。 +コンソールにはビルドエラーとlintの警告が表示されます。 +`Kotlin.defineModule is not a function` というエラーが出た場合、npmのキャッシュを削除してみてください。 + +```sh +rm -rf node_modules/.cache +``` + +### `npm run build` または `yarn build` + +`build` フォルダにプロダクト用のアプリをビルドします。 +これは、Reactが本番環境用にバンドルされていることを約束し、パフォーマンスのために最適化されたものです。 + +ビルドは圧縮され、ファイル名にはキャッシュを管理するためのハッシュが含まれています、これでアプリをデプロイする準備が整いました。 + +### アプリをデバッグする + +内蔵のJavaScriptデバッガを使用して、IntelliJ IDEA Ultimateで実行中のアプリを直接デバッグできます。 IDEは新しくChromeを実行し、それにデバッガを接続します。 + +`npm start` でアプリを起動します。 Kotlinのコードにブレークポイントを入れます。 +次に、右上の実行/デバッグ設定の一覧から `Debug in Chrome` を選択し、緑色のアイコンをクリックするか、macOSの場合は `^D` WindowsかLinuxの場合は `F9` を押してデバッグを開始します。 + +現在、デバッグは IntelliJ IDEA Ultimate 2017.3 のみでサポートされています。 + +ブラウザの開発者ツールでデバッグを行うこともできます。 + +## 哲学 + +* **依存関係は一つだけ:** ビルドの依存関係は一つだけです。これは、WebPackとその他の素晴らしいプロジェクトを使っていますが、それらの上でよりまとまりのある、精巧な体験を提供します。 + +* **設定不要:** 何も設定する必要はありません。 開発ビルドと本番ビルドの両方の素晴らしい設定があなたのためにされているので、あなたはコードを書くことだけに集中することができます。 + +* **ロックインがない:** いつでもカスタム設定に「eject」できます。 1つのコマンドを実行すると、すべての設定とビルドの依存関係がプロジェクトに直接移動されるので、中断したところからすぐに再開できます。 + +## 何を内包しているか + +生成されたプロジェクトは、以下のようなnpmモジュールを使用しています。: +* [Kotlin wrappers](https://github.com/JetBrains/kotlin-wrappers): [@jetbrains/kotlin-react](https://www.npmjs.com/package/@jetbrains/kotlin-react), [@jetbrains/kotlin-react-dom](https://www.npmjs.com/package/@jetbrains/kotlin-react-dom), [@jetbrains/kotlin-extensions](https://www.npmjs.com/package/@jetbrains/kotlin-extensions) +* [Kotlin DSL for HTML](https://www.npmjs.com/package/kotlinx-html) +* [Kotlin Compiler](https://www.npmjs.com/package/kotlin-compiler) +* [webpack](https://webpack.github.io/) with [webpack-dev-server](https://github.com/webpack/webpack-dev-server), [@jetbrains/kotlin-webpack-plugin](https://www.npmjs.com/package/@jetbrains/kotlin-webpack-plugin), [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) and [style-loader](https://github.com/webpack/style-loader) +* その他 + +## 何故これを選ぶか + +`create-react-kotlin-app` を使うと、KotlinとReactを使って新しいアプリケーションを素早く作成することができます。あなたの環境に、新しいKotlinアプリを構築するために必要なものがすべて揃得ることができます: + +* Kotlin と React の構文サポート。 +* KotlinのコードをJavaScriptに自動コンパイルするサーバー。 +* ソースマップを使って、本番用のJavaScript、CSS、および画像をバンドルするためのビルドスクリプト。 + +## 制限 + +* このプロジェクトでは、単体テストは現在サポートされていません。 現在Jest Kotlinラッパーに取り組んでいます。 乞うご期待! + +## カスタムセットアップへの変換 + +カスタムセットアップ変換ツールから「eject」してボイラーテンプレートジェネレーターとして使用することができます。 + +`npm run eject` を実行すると、すべてのファイルと推移的な依存関係(webpack、Kotlin Compilerなど)がプロジェクトに直接コピーされるので、それらを完全にコントロールできます。 +`npm start` や `npm run build` などのコマンドはまだ機能しますが、コピーされたスクリプトで実行するので、それらを細かく調整することができます。 この時点で、あなたのプロジェクトはあなた自身のものです。 + +**注意:これは不可逆的な操作です、「eject」した場合、もとに戻すことはできません** + +## 問題の報告と貢献 + +Please report issues on [YouTrack](https://youtrack.jetbrains.com/issues/CRKA) で問題を報告するようにしてください。GitHubのIssue機能は、このプロジェクトでは無効になっています。 + +このプロジェクトへの貢献は大歓迎です! [issues](https://youtrack.jetbrains.com/issues/CRKA?q=State:%20Open) を確認するか、[Slack](http://slack.kotlinlang.org/) の **#react** チャンネルでチャットしてください。 + +## 謝辞 + +このプロジェクトは、Facebook社の [Create React App](https://github.com/facebookincubator/create-react-app)をベースにしています。 +製作者の素晴らしいインスピレーションと仕事に感謝を述べます。 diff --git a/README-ko.md b/README-ko.md new file mode 100644 index 00000000..4a48b026 --- /dev/null +++ b/README-ko.md @@ -0,0 +1,183 @@ +[![Build Status](https://teamcity.jetbrains.com/app/rest/builds/buildType:JetBrainsUi_CreateReactKotlinApp/statusIcon.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=JetBrainsUi_CreateReactKotlinApp&guest=1) +[![JetBrains team project](http://jb.gg/badges/team.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) + +[English](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README.md) +[Japanese](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-ja.md) + +# Create React Kotlin App + +코틀린 안에서 별도의 빌드 설정 없이 React 앱을 만들어보세요. 이 프로젝트는 `초기의 프리뷰 버전`임을 유의하세요. + +## 훑어보기 + +**프로젝트를 진행하기 전 [JDK 8 버전](http://www.oracle.com/technetwork/java/index.html)이 설치되어 있는지 확인하세요.** Java 9는 아직 지원하지 않습니다. + +새 프로젝트를 작성하기: + +```sh +npx create-react-kotlin-app my-app +``` + +([npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) npm 5.2+ 버전 이상에서 사용할 수 있습니다. 그 이전의 npm 버전은 [여기](#installation) 를 참고하세요. + +프로젝트 시작하기: + +```sh +cd my-app/ +npm start +``` + +다음으로 [http://localhost:3000/](http://localhost:3000/)을 열어 앱을 확인할 수 있습니다.
+프로덕션에 배포할 준비가 되었다면, `npm run build` 명령어를 통해 미니파이된(minified) 결과물을 만들 수 있습니다. + +Create React Kotlin App은 코드에 집중할 수 있도록 코틀린, 웹팩 그리고 IntelliJ IDEA를 알아서 설정하기 때문에 간단하게 프로젝트만 생성하면 됩니다. + +## 시작하기 + +### 설치 + +create-react-kotlin-app 모듈을 전역적으로 설치합니다. + +```sh +npm install -g create-react-kotlin-app +``` + +만약 이미 `create-react-app`가 설치되어 있거나 혹은 `npx`를 사용한다면 설치 단계는 넘어가도 됩니다. + + +**6 버전 이상의 Node가 설치되어 있어야 합니다**. [nvm](https://github.com/creationix/nvm#usage)을 사용하여 서로 다른 프로젝트의 Node 버전으로 쉽게 전환할 수 있습니다. + +**이 도구는 Node 백엔드 역할을 하지 않습니다.** Node의 설치는 Create React Kotlin App 작성시에만 필요합니다. + +### 코틀린과 리액트 같이 사용하기 + +코틀린에서 리액트를 이용하여 애플리케이션을 개발하려면 [Kotlin wrapper for React](https://www.npmjs.com/package/@jetbrains/kotlin-react)이 필요합니다. [module's repository](https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-react)에서 이에 대한 문서와 예제에 대해 살펴볼수 있습니다. + +### 코틀린/자바스크립트 패키지 추가하기 + +Create React Kotlin App 기반의 코틀린으로 작성된 프로젝트에서는 **별도의 설정이 필요하지 않습니다.** 이러한 설정은 Create React Kotlin App에서 구성합니다. 예를 들어 [wrapper for React Router DOM](https://www.npmjs.com/package/@jetbrains/kotlin-react-router-dom)를 설치하기 위해 간단하게 `npm install @jetbrains/kotlin-react-router-dom` 명령어를 실행시키면 됩니다. + +### 앱 생성하기 + +새로운 앱을 실행하기 위해 다음의 명령어를 실행하세요: + +```sh +create-react-kotlin-app my-app +cd my-app +``` + +혹은 `create-react-app`가 설치 되어 있다면 다음의 명령어를 사용할 수 있습니다: + +```sh +create-react-app my-app --scripts-version react-scripts-kotlin +cd my-app +``` + +명령어를 실행시킨 경로 안에 `my-app` 폴더가 생성됩니다.
+프로젝트는 [IntelliJ IDEA](https://www.jetbrains.com/idea/)안에서 작업할 수 있도록 사전 구성됩니다. 만약 IntelliJ IDEA에 필요한 `.idea` 폴더가 생성되는 것을 원하지 않으면, `--no-idea` 옵션을 추가하세요.
+초기의 프로젝트의 구조가 생성되며, 각각의 모듈이 설치됩니다. + +``` +my-app/ + README.md + node_modules/ + package.json + .gitignore + public/ + favicon.ico + index.html + manifest.json + src/ + app/ + App.css + App.kt + index/ + index.css + index.kt + logo/ + kotlin.svg + Logo.css + Logo.kt + react.svg + ticker/ + Ticker.kt +``` + +이 프로젝트는 앱이 실행된 후 얼마의 시간이 지났는지를 보여주는 간단한 앱입니다.
+설치가 완료되면 프로젝트 폴더 안에서 몇가지의 명령어를 실행할 수 있습니다. + + +### `npm start` 혹은 `yarn start` + +개발 모드의 앱을 실행합니다.
+[http://localhost:3000](http://localhost:3000)을 통해 앱을 브라우저에서 볼 수 있습니다. + +앱의 코드 내에 새로운 수정이 생기면 페이지가 자동으로 새로고침 됩니다.
+경고 혹은 에러가 있을 경우, 콘솔창을 통해 볼 수 있습니다. + +만약 `Kotlin.defineModule is not a function` 와 같은 에러가 발생한다면, npm cache를 삭제하세요: + + rm -rf node_modules/.cache + +### `npm run build` 혹은 `yarn build` + +`build` 폴더에 프로덕션용 앱을 빌드합니다.
+리액트는 프로덕션 모드로 번들링되며, 번들된 결과물은 성능 최적화가 됩니다. + +빌드된 결과물은 압축되어 캐시 관리를 위해 각각의 파일 이름은 해쉬를 포함합니다. 이제 앱은 배포될 준비가 되었습니다. + +### 앱 디버깅 + +IntelliJ IDEA Ultimate에서 실행 중인 앱을 내장된 Javascript 디버거를 통해 디버깅할 수 있습니다. IDE는 새로운 인스턴스의 크롬을 실행하여 그 안에 디버거를 연결합니다. + +`npm start` 명령어를 통해 앱을 시작하여 코틀린 코드 내에 브레이크 포인트를 추가합니다. 그 다음 오른쪽 상단의 실행/디버깅 설정에서 `크롬에서 디버깅하기(Debug in Chrome)`을 선택합니다. 그리고 초록색 디버그 아이콘을 클릭하거나 맥북의 `^D` 혹은 윈도우와 리눅스에서는 `F9`를 통해 디버깅을 실행시킬 수 있습니다. + +현재는 IntelliJ IDEA Ultimate 2017.3에서만 디버깅을 지원합니다. + +또한 브라우저의 개발자 도구를 통해 애플리케이션을 디버깅할 수 있습니다. + +## 철학 + +* **하나의 의존성:** 하나의 빌드 의존성을 가집니다. 웹팩과 다른 훌륭한 프로젝트를 사용하고 있지만, 응집력 있는 정교한 경험을 제공합니다. + +* **별도의 설정이 필요하지 않습니다:** 별도의 설정을 구성할 필요가 없습니다. 개발 모드 및 프로덕션 모드의 효율적인 설정이 구성되어있기 때문에 코드를 작성하는 것에만 집중할 수 있습니다. + +* **별도의 잠금(Lock-In)제한이 없습니다:** 언제든 사용자가 스스로 설정을 할 수 있도록 "eject" 할 수 있습니다. 이 명령어를 통해 모든 설정과 빌드 의존성 모듈이 프로젝트 안으로 이동되며 eject된 설정 파일들을 자유롭게 설정할 수 있다. + +## 내부의 구성 요소 + +생성된 프로젝트는 다음의 npm 모듈을 사용합니다.: +* [Kotlin wrappers](https://github.com/JetBrains/kotlin-wrappers): [@jetbrains/kotlin-react](https://www.npmjs.com/package/@jetbrains/kotlin-react), [@jetbrains/kotlin-react-dom](https://www.npmjs.com/package/@jetbrains/kotlin-react-dom), [@jetbrains/kotlin-extensions](https://www.npmjs.com/package/@jetbrains/kotlin-extensions) +* [Kotlin DSL for HTML](https://www.npmjs.com/package/kotlinx-html) +* [Kotlin Compiler](https://www.npmjs.com/package/kotlin-compiler) +* [webpack](https://webpack.github.io/) with [webpack-dev-server](https://github.com/webpack/webpack-dev-server), [@jetbrains/kotlin-webpack-plugin](https://www.npmjs.com/package/@jetbrains/kotlin-webpack-plugin), [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) and [style-loader](https://github.com/webpack/style-loader) +* 기타 등등. + +## 왜 사용하나 + +`create-react-kotlin-app`을 이용하여 코틀린과 리액트를 이용할 수 있는 새로운 애플리케이션을 빠르게 구축할 수 있습니다. 새로운 코틀린 앱을 구축하는데 필요한 모든 환경을 제공합니다: +* 코틀린과 리액트 문법 지원합니다. +* 개발 서버는 코틀린 코드를 자바스크립트 코드로 자동으로 컴파일합니다. +* `build` 스크립트는 소스맵과 함께 자바스크립트, CSS 그리고 이미지를 프로덕션 용으로 빌드합니다. + +## 한계 + +* 현재 이 프로젝트는 단위 테스트를 지원하지 않습니다. 현재 Jest Kotlin wrapper를 만들고 있으니 앞으로 지켜봐주세요. + +## 사용자 설정 변환 + +툴을 이용하여 "eject" 할 수 있으며, 보일러플레이트 생성기로서 사용할 수 있습니다. + +`npm run eject`를 사용하면 모든 설정 파일과 변환 모듈(웹팩, 코틀린 컴파일러, 기타 등등)들이 프로젝트에 바로 복사되며 이를 통해 모든 설정을 자유롭게 구성할 수 있습니다. `npm start`와 `npm run build` 명령어는 기존과 같이 동작하되, 복사된 설정 파일에 따라 동작하기 때문에 자유롭게 구성하면 됩니다. + +**주의: 실행은 단방향이며, 한번 `eject`되면 다시 복구할 수 없습니다.** + +## 프로젝트 기여하기와 이슈 리포팅하기 + +[YouTrack](https://youtrack.jetbrains.com/issues/CRKA)에 이슈를 등록해주세요. 이 프로젝트는 GitHub의 이슈를 사용하지 않습니다. + +이 프로젝트에 대한 기여를 환영합니다! 현재 생성된 [issues](https://youtrack.jetbrains.com/issues/CRKA?q=State:%20Open)를 보거나 [Slack](http://slack.kotlinlang.org/)의 **#react** 채널에서 우리와 함께 이야기할 수 있습니다. + +## 감사의 말 + +이 프로젝트는 페이스북의 [Create React App](https://github.com/facebookincubator/create-react-app)를 기반으로 합니다. 프로젝트 작성자의 작업과 영감에 대하여 감사드립니다. \ No newline at end of file diff --git a/README-zh_cn.md b/README-zh_cn.md new file mode 100644 index 00000000..9481da7c --- /dev/null +++ b/README-zh_cn.md @@ -0,0 +1,192 @@ +[![Build Status](https://teamcity.jetbrains.com/app/rest/builds/buildType:JetBrainsUi_CreateReactKotlinApp/statusIcon.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=JetBrainsUi_CreateReactKotlinApp&guest=1) +[![JetBrains team project](http://jb.gg/badges/team.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) + +[Japanese](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-ja.md) +[Korean](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-ko.md) +[Chinese](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-zh_cn.md) + +# Create React Kotlin App + +在不填加 build 配置的情况下,使用[Kotlin](https://kotlinlang.org/)创建[React](https://facebook.github.io/react/)应用。 + +请注意这是一个 **早期预览版本** 。 + +## 快速预览 + +**在开始之前,请确保你安装了[JDK 8](http://www.oracle.com/technetwork/java/index.html)** ,Java 9 目前是不支持的。 + +创建一个新的项目: + +```sh +npx create-react-kotlin-app my-app +``` +([npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) 存在于 npm 5.2+ 或更高版本,如果你使用旧的npm版本,请参见[安装](#安装)) + +运行这个项目 + +```sh +cd my-app/ +npm start +``` +然后打开 [http://localhost:3000/](http://localhost:3000/) 来查看你的应用。
+当你做好部署到生产的准备,使用 `npm run build` 创建一个 minified bundle + +Create React Kotlin App 将会配置 Kotlin, webpack 和 IntelliJ IDEA ,你可以专注于你的代码。 + +仅仅创建一个项目,你就可以轻松开始。 + +## 开始 + +### 安装 + +全局安装: + +```sh +npm install -g create-react-kotlin-app +``` + +如果你已经安装了 `create-react-app` 或者你在使用 `npx`, 你可以跳过这步。 + + +**你需要使用 Node >= 6 的版本**. 你可以使用 [nvm](https://github.com/creationix/nvm#usage) 在不同项目间切换node版本 + +**This tool doesn’t assume a Node backend**. The Node installation is only required for Create React Kotlin App itself. + +### 使用Kotlin编写React应用 + +要使用Kotlin编写React应用,你需要使用一个[Kotlin的React包装](https://www.npmjs.com/package/@jetbrains/kotlin-react), +你可以在[这里](https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-react)找到它的文档和示例 + +### 添加 Kotlin/JS + +**不需要任何配置**来为基于Create React Kotlin App创建的项目添加用Kotlin编写的包,我们会为你做好这一切。 +比如,你可以简单地运行 `npm install @jetbrains/kotlin-react-router-dom` 来安装 [wrapper for React Router DOM](https://www.npmjs.com/package/@jetbrains/kotlin-react-router-dom). + + +### 创建一个应用 + +要创建一个新的应用,运行: + +```sh +create-react-kotlin-app my-app +cd my-app +``` +如果你安装了 `create-react-app` ,你可以运行: + +```sh +create-react-app my-app --scripts-version react-scripts-kotlin +cd my-app +``` +它将创建一个叫 `my-app` 的文件夹在当前目录下。
+项目将被自动预配置为使用 [IntelliJ IDEA](https://www.jetbrains.com/idea/) 开发。如果你不想创建 `.idea` 这个被 IntelliJ IDEA 需要的文件夹,请在运行时添加 `--no-idea` 选项。
+以下初始的项目结构将被自动创建,依赖将会自动安装: + + +``` +my-app/ + README.md + node_modules/ + package.json + .gitignore + public/ + favicon.ico + index.html + manifest.json + src/ + app/ + App.css + App.kt + index/ + index.css + index.kt + logo/ + kotlin.svg + Logo.css + Logo.kt + react.svg + ticker/ + Ticker.kt +``` + +这是一个简单的应用程序,显示了自打开应用程序以来经过的时间。
+安装完成后,您可以在项目文件夹中运行一些命令: + +### `npm start` or `yarn start` + +在开发模式下运行应用
+打开 [http://localhost:3000](http://localhost:3000) 在浏览器中查看 + +当你编辑时,页面会自动刷新
+你将在控制台中看到构建错误和 lint 警告 + +如果你遇到了 `Kotlin.defineModule is not a function` 错误,尝试删除npm缓存: + + rm -rf node_modules/.cache + +### `npm run build` or `yarn build` + +在 `build` 目录中为生产环境构建
+为生产环境构建的版本位于 `build` 目录中
+它确保了 React 使用生产模式,并且这个构建已经过优化,可以获得最佳性能 + +这个构建是 minified 过的,且文件名包含了用于缓存管理的哈希 + +### 调试应用 + +你可以使用 IntelliJ IDEA 旗舰版内置的 JavaScript 调试器调试运行中的应用。IDE将会启动一个新的Chrome实力,并为此添加调试器。 + +使用 `npm start` 启动你的应用,并在Kotlin代码中添加断点 + +在右上角的 run/debug configurations 中选择 `Debug in Chrome` 并点击绿色的调式按钮,或按下 `^D`(在 Mac OS 上) / `F9` (在Windows和Linux上)来开始调试。 + +目前,调试器只被 IntelliJ IDEA Ultimate 2017.3 支持 + +你也可以使用浏览器中的开发者工具调试你的应用 + + +## Philosophy + +* **一个依赖:** 只有一个构建依赖。它使用了webpack和其他出色的项目,但是在它们之上提供了富有凝聚力的开发体验。 + +* **无需配置:** 你什么都不需要配置。为您处理了开发和生产版本的合理且良好配置,因此您可以专注于编写代码。 + +* **No Lock-In:** 你可以随时回到你的个性化设置。 运行一个命令,所有配置和构建依赖项都将直接移到您的项目中,您可以轻松回到上次停下来的地方。 + +## 这里边有什么? + +生成的项目使用了以下 npm 模块: +* [Kotlin wrappers](https://github.com/JetBrains/kotlin-wrappers): [@jetbrains/kotlin-react](https://www.npmjs.com/package/@jetbrains/kotlin-react), [@jetbrains/kotlin-react-dom](https://www.npmjs.com/package/@jetbrains/kotlin-react-dom), [@jetbrains/kotlin-extensions](https://www.npmjs.com/package/@jetbrains/kotlin-extensions) +* [Kotlin DSL for HTML](https://www.npmjs.com/package/kotlinx-html) +* [Kotlin Compiler](https://www.npmjs.com/package/kotlin-compiler) +* [webpack](https://webpack.github.io/) with [webpack-dev-server](https://github.com/webpack/webpack-dev-server), [@jetbrains/kotlin-webpack-plugin](https://www.npmjs.com/package/@jetbrains/kotlin-webpack-plugin), [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) and [style-loader](https://github.com/webpack/style-loader) +* and others. + +## 为什么使用这个? + +通过 `create-react-kotlin-app` 你可以快速开启一个使用 React 和 Kotlin 编写的应用。 你的环境将包含构建Kotlin React应用的一切: +* Kotlin和React语法支持 +* 一个开发服务来自动编译你的Kotlin代码到JavaScript +* 一个build脚本,用于将JavaScript,CSS和图像用于生产,并带有 source maps + +## 限制 + +* 当前项目暂时不支持使用单元测试,我们现在致力于 Jest Kotlin wrapper 敬请关注! + +## 转换为自定义设置 + +你可以将项目从工具中“弹出”,并像模板生成器一样使用。 + +运行 `npm run eject` 复制所有配置文件和可转移的依赖 (webpack, Kotlin Compiler, etc) 到你的项目中,这使你拥有对项目的完整控制。诸如 `npm start` 和 `npm run build` 这样的命令将继续工作,但它们将指向复制出的脚本,因此你可以对其进行调整。 至此,你可以自由发挥了。 + +**注意:这是个单向操作,一旦你 `eject`,你将不能返回!** + +## 贡献和报告问题 + +请在 [YouTrack](https://youtrack.jetbrains.com/issues/CRKA) 上报告问题,本项目的 Github issue 已经关闭 + +欢迎大家为此项目做贡献! 请查看这个打开的 [issues](https://youtrack.jetbrains.com/issues/CRKA?q=State:%20Open) ,或者在 **#react** [Slack](http://slack.kotlinlang.org/) 频道中与我们讨论 + +## 致谢 + +这个项目基于 Facebook 的 [Create React App](https://github.com/facebookincubator/create-react-app). 非常感谢其作者的工作和启发。 + diff --git a/README.md b/README.md index 6725ff98..006bf815 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ [![Build Status](https://teamcity.jetbrains.com/app/rest/builds/buildType:JetBrainsUi_CreateReactKotlinApp/statusIcon.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=JetBrainsUi_CreateReactKotlinApp&guest=1) [![JetBrains team project](http://jb.gg/badges/team.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) -# Create React Kotlin App +[Japanese](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-ja.md) +[Korean](https://github.com/JetBrains/create-react-kotlin-app/blob/master/README-ko.md) + +# Create React Kotlin App Create [React](https://facebook.github.io/react/) apps in [Kotlin](https://kotlinlang.org/) with no build configuration. -Please note that this is an **early preview version**. +Please note that this is an **early preview version**. ## Quick Overview -Make sure you have [JDK 8](http://www.oracle.com/technetwork/java/index.html) installed before proceeding. Java 9 is not supported yet. - -Install `create-react-kotlin-app` using npm: -```sh -npm install -g create-react-kotlin-app -``` +**Make sure you have [JDK 8 or newer version](http://www.oracle.com/technetwork/java/index.html) installed before proceeding.** Create a new project: + ```sh -create-react-kotlin-app my-app +npx create-react-kotlin-app my-app ``` +([npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) comes with npm 5.2+ and higher. See [Installation](#installation) for older npm versions.) Run the project: ```sh @@ -44,7 +44,7 @@ Install it once globally: npm install -g create-react-kotlin-app ``` -You can skip this step if you have `create-react-app` already installed. +You can skip this step if you have `create-react-app` already installed or you're using `npx`. **You’ll need to have Node >= 6 on your machine**. You can use [nvm](https://github.com/creationix/nvm#usage) to easily switch between Node versions for different projects. @@ -52,9 +52,14 @@ You can skip this step if you have `create-react-app` already installed. ### Using React with Kotlin -To develop applications in Kotlin that use React you need to use a [Kotlin wrapper for React](https://www.npmjs.com/package/@jetbrains/kotlin-react). +To develop applications in Kotlin that use React you need to use a [Kotlin wrapper for React](https://www.npmjs.com/package/@jetbrains/kotlin-react). You can find a documentation for it and examples in the [module's repository](https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-react). +### Adding Kotlin/JS packages + +**No configuration is required** to add packages written in Kotlin to a project based on Create React Kotlin App, we take care of it for you. +For example, you can simply run `npm install @jetbrains/kotlin-react-router-dom` to install the [wrapper for React Router DOM](https://www.npmjs.com/package/@jetbrains/kotlin-react-router-dom). + ### Creating an App To create a new app, run: @@ -112,6 +117,10 @@ Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload automatically when you make edits.
You will see build errors and lint warnings in the console. +If you are getting a `Kotlin.defineModule is not a function` error, try deleting the npm cache: + + rm -rf node_modules/.cache + ### `npm run build` or `yarn build` Builds the app for production to the `build` folder.
@@ -156,7 +165,7 @@ With `create-react-kotlin-app` you can quickly bootstrap a new application using ## Limitations -* Unit testing is currently not supported in this project. We're now working on the Jest Kotlin wrapper. Stay tuned! +* Unit testing is currently not supported in this project. We're now working on the Jest Kotlin wrapper. Unit-testing React is tracked in [KT-49610](https://youtrack.jetbrains.com/issue/KT-49610). Stay tuned! ## Converting to a Custom Setup @@ -170,8 +179,9 @@ Running `npm run eject` copies all configuration files and transitive dependenci Please report issues on [YouTrack](https://youtrack.jetbrains.com/issues/CRKA), GitHub issues are disabled for this project. -Contributions to this project are welcome! Please see the open [issues](https://youtrack.jetbrains.com/issues/CRKA?q=State:%20Open) or chat with us on the **#react** channel in our [Slack](http://slack.kotlinlang.org/). +Contributions to this project are welcome! Please see the open [issues](https://youtrack.jetbrains.com/issues/CRKA?q=State:%20Open) or chat with us on the **#react** channel in our [Slack](http://slack.kotlinlang.org/). ## Acknowledgements This project is based on Facebook's [Create React App](https://github.com/facebookincubator/create-react-app). Many thanks to its authors for their work and inspiration. + diff --git a/dependencies.yml b/dependencies.yml deleted file mode 100644 index 7a484025..00000000 --- a/dependencies.yml +++ /dev/null @@ -1,22 +0,0 @@ -collectors: -- type: js-lerna - path: / - settings: - collect_root: true - bootstrap_command: yarn - actors: - # batch PR for minor and patch updates - - type: js-lerna - versions: "L.Y.Y" - settings: - batch_mode: true - bootstrap_command: yarn - github_labels: - - dependencies - # separate PRs for major updates - - type: js-lerna - versions: "Y.0.0" - settings: - bootstrap_command: yarn - github_labels: - - dependencies diff --git a/lerna.json b/lerna.json index 49748344..7d163241 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "lerna": "2.4.0", + "lerna": "2.11.0", "npmClient": "yarn", "useWorkspaces": true, "version": "independent", diff --git a/package.json b/package.json index 007fb594..9badcdc6 100644 --- a/package.json +++ b/package.json @@ -14,19 +14,21 @@ "precommit": "lint-staged" }, "devDependencies": { - "@jetbrains/kotlin-extensions": "^1.0.0-pre.15", - "@jetbrains/kotlin-react": "^16.2.0-pre.15", - "@jetbrains/kotlin-react-dom": "^16.2.0-pre.15", - "eslint": "4.16.0", - "husky": "^0.14.3", - "kotlin": "^1.2.0", - "kotlinx-html": "^0.6.8", - "lerna": "^2.4.0", - "lerna-changelog": "^0.7.0", - "lint-staged": "^6.0.0", - "prettier": "^1.7.4", - "react": "^16.2.0", - "react-dom": "^16.2.0" + "@jetbrains/kotlin-extensions": "^1.0.1-pre.89", + "@jetbrains/kotlin-react": "^16.9.0-pre.91", + "@jetbrains/kotlin-react-dom": "^16.9.0-pre.89", + "core-js": "^3.20.2", + "eslint": "^7.32.0", + "husky": "^7.0.4", + "kotlin": "~1.5.32", + "kotlinx-coroutines-core": "^1.5.2", + "kotlinx-html": "^0.7.2", + "lerna": "^4.0.0", + "lerna-changelog": "^2.2.0", + "lint-staged": "^10.5.4", + "prettier": "^2.5.1", + "react": "^17.0.2", + "react-dom": "^16.12.0" }, "lint-staged": { "*.js": [ @@ -38,7 +40,7 @@ "git rm --cached" ], "engines": { - "node": ">=8.0.0", + "node": ">=14.18.2", "yarn": ">=1.0.0" } } diff --git a/packages/create-react-kotlin-app/.nvmrc b/packages/create-react-kotlin-app/.nvmrc new file mode 100644 index 00000000..ca4a60d1 --- /dev/null +++ b/packages/create-react-kotlin-app/.nvmrc @@ -0,0 +1 @@ +v14.18.2 diff --git a/packages/create-react-kotlin-app/createReactApp.js b/packages/create-react-kotlin-app/createReactApp.js index dd0d432a..6dc4baca 100755 --- a/packages/create-react-kotlin-app/createReactApp.js +++ b/packages/create-react-kotlin-app/createReactApp.js @@ -55,7 +55,7 @@ const program = new commander.Command(packageJson.name) .version(packageJson.version) .arguments('') .usage(`${chalk.green('')} [options]`) - .action(name => { + .action((name) => { projectName = name; }) .option('--verbose', 'print additional logs') @@ -114,7 +114,7 @@ if (typeof projectName === 'undefined') { function printValidationResults(results) { if (typeof results !== 'undefined') { - results.forEach(error => { + results.forEach((error) => { console.error(chalk.red(` * ${error}`)); }); } @@ -167,9 +167,7 @@ function createApp(name, verbose, version, template) { if (!semver.satisfies(process.version, '>=6.0.0')) { console.log( chalk.yellow( - `You are using Node ${ - process.version - } so the project will be boostrapped with an old unsupported version of tools.\n\n` + + `You are using Node ${process.version} so the project will be boostrapped with an old unsupported version of tools.\n\n` + `Please update to Node 6 or higher for a better, fully supported experience.\n` ) ); @@ -184,9 +182,7 @@ function createApp(name, verbose, version, template) { if (npmInfo.npmVersion) { console.log( chalk.yellow( - `You are using npm ${ - npmInfo.npmVersion - } so the project will be boostrapped with an old unsupported version of tools.\n\n` + + `You are using npm ${npmInfo.npmVersion} so the project will be boostrapped with an old unsupported version of tools.\n\n` + `Please update to npm 3 or higher for a better, fully supported experience.\n` ) ); @@ -234,7 +230,7 @@ function install(useYarn, dependencies, verbose, isOnline) { } const child = spawn(command, args, { stdio: 'inherit' }); - child.on('close', code => { + child.on('close', (code) => { if (code !== 0) { reject({ command: `${command} ${args.join(' ')}`, @@ -260,13 +256,13 @@ function run( console.log('Installing packages. This might take a couple minutes.'); getPackageName(packageToInstall) - .then(packageName => - checkIfOnline(useYarn).then(isOnline => ({ + .then((packageName) => + checkIfOnline(useYarn).then((isOnline) => ({ isOnline: isOnline, packageName: packageName, })) ) - .then(info => { + .then((info) => { const isOnline = info.isOnline; const packageName = info.packageName; console.log( @@ -280,7 +276,7 @@ function run( () => packageName ); }) - .then(packageName => { + .then((packageName) => { checkNodeVersion(packageName); // Since react-scripts has been installed with --save @@ -307,7 +303,7 @@ function run( ); } }) - .catch(reason => { + .catch((reason) => { console.log(); console.log('Aborting installation.'); if (reason.command) { @@ -327,8 +323,8 @@ function run( 'node_modules', ]; const currentFiles = fs.readdirSync(path.join(root)); - currentFiles.forEach(file => { - knownGeneratedFiles.forEach(fileToMatch => { + currentFiles.forEach((file) => { + knownGeneratedFiles.forEach((fileToMatch) => { // This will catch `(npm-debug|yarn-error|yarn-debug).log*` files // and the rest of knownGeneratedFiles. if ( @@ -395,7 +391,7 @@ function getTemporaryDirectory() { function extractStream(stream, dest) { return new Promise((resolve, reject) => { stream.pipe( - unpack(dest, err => { + unpack(dest, (err) => { if (err) { reject(err); } else { @@ -410,7 +406,7 @@ function extractStream(stream, dest) { function getPackageName(installPackage) { if (installPackage.indexOf('.tgz') > -1) { return getTemporaryDirectory() - .then(obj => { + .then((obj) => { let stream; if (/^http/.test(installPackage)) { stream = hyperquest(installPackage); @@ -419,12 +415,12 @@ function getPackageName(installPackage) { } return extractStream(stream, obj.tmpdir).then(() => obj); }) - .then(obj => { + .then((obj) => { const packageName = require(path.join(obj.tmpdir, 'package.json')).name; obj.cleanup(); return packageName; }) - .catch(err => { + .catch((err) => { // The package name could be with or without semver version, e.g. react-scripts-0.2.0-alpha.1.tgz // However, this function returns package name only without semver version. console.log( @@ -458,9 +454,7 @@ function checkNpmVersion() { let hasMinNpm = false; let npmVersion = null; try { - npmVersion = execSync('npm --version') - .toString() - .trim(); + npmVersion = execSync('npm --version').toString().trim(); hasMinNpm = semver.gte(npmVersion, '3.0.0'); } catch (err) { // ignore @@ -522,7 +516,9 @@ function checkAppName(appName) { )} because a dependency with the same name exists.\n` + `Due to the way npm works, the following names are not allowed:\n\n` ) + - chalk.cyan(allDependencies.map(depName => ` ${depName}`).join('\n')) + + chalk.cyan( + allDependencies.map((depName) => ` ${depName}`).join('\n') + ) + chalk.red('\n\nPlease choose a different project name.') ); process.exit(1); @@ -594,7 +590,7 @@ function isSafeToCreateProjectIn(root) { '.hgignore', '.hgcheck', ]; - return fs.readdirSync(root).every(file => validFiles.indexOf(file) >= 0); + return fs.readdirSync(root).every((file) => validFiles.indexOf(file) >= 0); } function checkIfOnline(useYarn) { @@ -604,8 +600,8 @@ function checkIfOnline(useYarn) { return Promise.resolve(true); } - return new Promise(resolve => { - dns.lookup('registry.yarnpkg.com', err => { + return new Promise((resolve) => { + dns.lookup('registry.yarnpkg.com', (err) => { resolve(err === null); }); }); diff --git a/packages/create-react-kotlin-app/package.json b/packages/create-react-kotlin-app/package.json index d7cee3ec..cba1680b 100644 --- a/packages/create-react-kotlin-app/package.json +++ b/packages/create-react-kotlin-app/package.json @@ -1,6 +1,6 @@ { "name": "create-react-kotlin-app", - "version": "1.0.6", + "version": "2.1.0", "keywords": [ "react" ], @@ -8,7 +8,7 @@ "repository": "JetBrains/create-react-kotlin-app", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=14.18.2" }, "bugs": { "url": "https://youtrack.jetbrains.com/issues/CRKA" @@ -21,14 +21,14 @@ "create-react-kotlin-app": "./index.js" }, "dependencies": { - "chalk": "^2.3.0", - "commander": "^2.9.0", - "cross-spawn": "^6.0.0", - "fs-extra": "^5.0.0", - "hyperquest": "^2.1.2", - "semver": "^5.0.3", - "tar-pack": "^3.4.0", - "tmp": "0.0.33", + "chalk": "^2.4.2", + "commander": "^3.0.2", + "cross-spawn": "^7.0.3", + "fs-extra": "^10.0.0", + "hyperquest": "^2.1.3", + "semver": "^7.3.5", + "tar-pack": "^3.4.1", + "tmp": "^0.2.1", "validate-npm-package-name": "^3.0.0" } } diff --git a/packages/gen-idea-libs/.nvmrc b/packages/gen-idea-libs/.nvmrc new file mode 100644 index 00000000..ca4a60d1 --- /dev/null +++ b/packages/gen-idea-libs/.nvmrc @@ -0,0 +1 @@ +v14.18.2 diff --git a/packages/gen-idea-libs/generate.js b/packages/gen-idea-libs/generate.js index af49582e..32b277ad 100644 --- a/packages/gen-idea-libs/generate.js +++ b/packages/gen-idea-libs/generate.js @@ -9,10 +9,18 @@ const fs = require('fs'); 'kotlin-extensions': require.resolve('@jetbrains/kotlin-extensions'), 'kotlin-react': require.resolve('@jetbrains/kotlin-react'), 'kotlin-react-dom': require.resolve('@jetbrains/kotlin-react-dom'), - 'kotlinx-html-js': require.resolve('@hypnosphi/kotlinx-html-js') + 'kotlinx-html-js': require.resolve('kotlinx-html') }, '.') */ +const findIml = function (directory) { + const imlList = fs.readdirSync(directory).filter((element) => { + var extName = path.extname(element); + return extName === '.iml'; + }); + return (imlList.length > 0 && imlList[0]) || null; +}; + module.exports = function generate(packages, projectDir, imlPath) { const libTemplate = fs.readFileSync( path.join(__dirname, './libTemplate.xml'), @@ -26,26 +34,39 @@ module.exports = function generate(packages, projectDir, imlPath) { iml = fs.readFileSync(_imlPath, 'utf8'); } else { try { - _imlPath = path.join( - projectDir, - '.idea', - `${path.basename(path.resolve(projectDir))}.iml` - ); + const ideaDir = path.join(projectDir, '.idea'); + let imlFileName = findIml(ideaDir); + _imlPath = path.join(ideaDir, imlFileName); + iml = fs.readFileSync(_imlPath, 'utf8'); } catch (e) { _imlPath = path.join( projectDir, `${path.basename(path.resolve(projectDir))}.iml` ); - iml = fs.readFileSync(_imlPath, 'utf8'); + try { + let imlFileName = findIml(projectDir); + _imlPath = path.join(projectDir, imlFileName); + iml = fs.readFileSync(_imlPath, 'utf8'); + } catch (err) { + console.warn( + 'gen-idea-libs failed to find %project-name%.iml file, skipping generation' + ); + return; + } } } - Object.keys(packages).forEach(name => { + Object.keys(packages).forEach((name) => { const pkg = packages[name]; const classes = path.relative(projectDir, path.join(pkg, '..')); fs.writeFile( path.join(projectDir, `.idea/libraries/${name.replace(/-/g, '_')}.xml`), - libTemplate.replace(/%name%/g, name).replace(/%classes%/g, classes) + libTemplate.replace(/%name%/g, name).replace(/%classes%/g, classes), + (err) => { + if (err) { + throw err; + } + } ); const dep = depTemplate.replace(/%name%/g, name); @@ -53,5 +74,9 @@ module.exports = function generate(packages, projectDir, imlPath) { iml = iml.replace(/(\n\s+)<\/component>/, `$1 ${dep}$&`); } }); - fs.writeFile(_imlPath, iml); + fs.writeFile(_imlPath, iml, (err) => { + if (err) { + throw err; + } + }); }; diff --git a/packages/gen-idea-libs/libTemplate.xml b/packages/gen-idea-libs/libTemplate.xml index 23b2aead..464cbd30 100644 --- a/packages/gen-idea-libs/libTemplate.xml +++ b/packages/gen-idea-libs/libTemplate.xml @@ -1,5 +1,5 @@ - + diff --git a/packages/gen-idea-libs/package.json b/packages/gen-idea-libs/package.json index a0492549..71572e89 100644 --- a/packages/gen-idea-libs/package.json +++ b/packages/gen-idea-libs/package.json @@ -1,12 +1,12 @@ { "name": "@jetbrains/gen-idea-libs", - "version": "1.0.7", + "version": "2.0.0", "description": "Generates IntelliJ IDEA library configuration from given Kotlin/JS npm dependencies", "main": "generate", "author": "Filipp Riabchun", "repository": "JetBrains/create-react-kotlin-app", "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": ">=14.18.2" } } diff --git a/packages/kotlin-webpack-plugin/.nvmrc b/packages/kotlin-webpack-plugin/.nvmrc new file mode 100644 index 00000000..ca4a60d1 --- /dev/null +++ b/packages/kotlin-webpack-plugin/.nvmrc @@ -0,0 +1 @@ +v14.18.2 diff --git a/packages/kotlin-webpack-plugin/README.md b/packages/kotlin-webpack-plugin/README.md index dc4279da..aa52eef0 100644 --- a/packages/kotlin-webpack-plugin/README.md +++ b/packages/kotlin-webpack-plugin/README.md @@ -8,6 +8,9 @@ This package allows compiling [Kotlin](https://kotlinlang.org/) files to JavaScr npm i @jetbrains/kotlin-webpack-plugin --save-dev ``` +## Requirements +This plugin requires a minimum of Node v8.6.0 and Webpack v4.0.0. To use this plugin with Webpack v3.0.0, you need to use v1.2.11 of this plugin. + ## Usage Example of webpack configuration: @@ -50,4 +53,4 @@ module.exports = { }; ``` -You can find a sample configuration in the [example](./example) folder. \ No newline at end of file +You can find a sample configuration in the [example](https://github.com/JetBrains/create-react-kotlin-app/tree/master/packages/kotlin-webpack-plugin/example) folder. diff --git a/packages/kotlin-webpack-plugin/dce-plugin.js b/packages/kotlin-webpack-plugin/dce-plugin.js index 4919fe6e..306cd1b5 100644 --- a/packages/kotlin-webpack-plugin/dce-plugin.js +++ b/packages/kotlin-webpack-plugin/dce-plugin.js @@ -14,12 +14,12 @@ function eliminateDeadCode(args) { let hasErrors = false; let errors = ''; - compilation.stderr.on('data', data => { + compilation.stderr.on('data', (data) => { hasErrors = true; errors += data.toString(); }); - compilation.on('error', err => { + compilation.on('error', (err) => { hasErrors = true; errors += 'kotlin-dce-js failed'; errors += JSON.stringify(err); @@ -33,6 +33,8 @@ function optimize(options) { const args = [ '-output-dir', options.outputDir, + '-keep', + options.moduleName, options.outputPath, options.runtimePath || require.resolve('kotlin'), ].concat(options.librariesPaths); diff --git a/packages/kotlin-webpack-plugin/example/main.kt b/packages/kotlin-webpack-plugin/example/main.kt index a7a03650..db134c42 100644 --- a/packages/kotlin-webpack-plugin/example/main.kt +++ b/packages/kotlin-webpack-plugin/example/main.kt @@ -1,7 +1,7 @@ package example +import kotlinx.browser.document import react.dom.* -import kotlin.browser.* fun main(args: Array) { render(document.getElementById("app")) { diff --git a/packages/kotlin-webpack-plugin/example/webpack.config.js b/packages/kotlin-webpack-plugin/example/webpack.config.js index 1d0cf187..be2cfafe 100644 --- a/packages/kotlin-webpack-plugin/example/webpack.config.js +++ b/packages/kotlin-webpack-plugin/example/webpack.config.js @@ -34,12 +34,8 @@ module.exports = { src: __dirname, verbose: true, optimize: true, - libraries: [ - '@jetbrains/kotlin-extensions', - '@jetbrains/kotlin-react', - '@jetbrains/kotlin-react-dom', - 'kotlinx-html', - ].map(pkg => require.resolve(pkg)), + librariesAutoLookup: true, + packagesContents: [require('../../react-scripts/package.json')], }), new HtmlWebpackPlugin({ template: path.join(__dirname, 'index.html'), diff --git a/packages/kotlin-webpack-plugin/libraries-lookup.js b/packages/kotlin-webpack-plugin/libraries-lookup.js new file mode 100644 index 00000000..e0dea53d --- /dev/null +++ b/packages/kotlin-webpack-plugin/libraries-lookup.js @@ -0,0 +1,50 @@ +'use strict'; +const fs = require('fs'); +const path = require('path'); + +function lookupInPackage(pkg) { + return ( + [ + ...Object.keys(pkg.dependencies || {}), + ...Object.keys(pkg.devDependencies || {}), + ...Object.keys(pkg.peerDependencies || {}), + ] + // We provide the Kotlin runtime externally, so we aren't looking for it + .filter((dependencyName) => dependencyName !== 'kotlin') + .map((dependencyName) => { + try { + let main; + if (require.resolve.paths) { + // resolve only searches this scripts node_modules for the dependency in newer versions + const paths = require.resolve.paths(dependencyName); + paths.push(path.resolve(process.cwd(), 'node_modules')); + main = require.resolve(dependencyName, { paths }); + } else { + main = require.resolve(dependencyName); + } + // Kotlin libraries contain a .meta.js file + const hasKotlinMetaFile = fs.existsSync( + main.replace(/(\.js)?$/, '.meta.js') + ); + return hasKotlinMetaFile ? main : null; + } catch (err) { + return null; + } + }) + .filter((dependencyMainFilePath) => !!dependencyMainFilePath) + ); +} + +function removeDuplicates(libraries) { + return [...new Set(libraries)]; +} + +module.exports = { + lookupKotlinLibraries(packages) { + const libraries = packages.reduce((acc, pkg) => { + return [...acc, ...lookupInPackage(pkg)]; + }, []); + + return removeDuplicates(libraries); + }, +}; diff --git a/packages/kotlin-webpack-plugin/package.json b/packages/kotlin-webpack-plugin/package.json index 752f81c8..ee0f658e 100644 --- a/packages/kotlin-webpack-plugin/package.json +++ b/packages/kotlin-webpack-plugin/package.json @@ -1,14 +1,14 @@ { "name": "@jetbrains/kotlin-webpack-plugin", - "version": "1.2.1", + "version": "3.0.2", "description": "Kotlin plugin for webpack", "main": "plugin.js", "repository": "JetBrains/create-react-kotlin-app", "scripts": { - "start": "webpack-dev-server -d --inline --hot --devtool source-map --config example/webpack.config.js", - "build-example": "rm -rf example/build/ && webpack --config example/webpack.config.js --bail --devtool source-map", - "debug-build": "node --inspect-brk ./node_modules/.bin/webpack --config example/webpack.config.js", - "debug-dev-server": "node --inspect-brk ./node_modules/.bin/webpack-dev-server --config example/webpack.config.js", + "start": "webpack-dev-server --mode development --inline --hot --devtool source-map --config example/webpack.config.js", + "build-example": "rm -rf example/build/ && webpack --mode production --config example/webpack.config.js --bail --devtool source-map", + "debug-build": "node --inspect-brk ./node_modules/.bin/webpack --mode development --config example/webpack.config.js", + "debug-dev-server": "node --inspect-brk ./node_modules/.bin/webpack-dev-server --mode development --config example/webpack.config.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ @@ -16,26 +16,28 @@ "Kotlin" ], "engines": { - "node": ">=6" + "node": ">=14.18.2" }, "author": "Andrey Skladchikov ", "license": "Apache-2.0", "files": [ "plugin.js", + "libraries-lookup.js", "dce-plugin.js" ], "dependencies": { - "@jetbrains/kotlinc-js-api": "^1.2.3", - "fs-extra": "5.0.0", - "glob": "7.1.2", - "globby": "7.1.1", - "kotlin-compiler": "^1.2.1", - "read-dir-files": "^0.1.1" + "@jetbrains/kotlinc-js-api": "^2.0.1", + "fs-extra": "^10.0.0", + "glob": "^7.1.6", + "globby": "^10.0.1", + "kotlin-compiler": "^1.3.61", + "webpack-log": "^3.0.2" }, "devDependencies": { - "html-webpack-plugin": "^2.30.1", - "source-map-loader": "0.2.3", - "webpack": "^3.7.1", - "webpack-dev-server": "2.11.1" + "html-webpack-plugin": "^3.2.0", + "source-map-loader": "^0.2.4", + "webpack": "^4.46.0", + "webpack-cli": "^3.3.10", + "webpack-dev-server": "^4.7.2" } } diff --git a/packages/kotlin-webpack-plugin/plugin.js b/packages/kotlin-webpack-plugin/plugin.js index ca917718..165149fb 100644 --- a/packages/kotlin-webpack-plugin/plugin.js +++ b/packages/kotlin-webpack-plugin/plugin.js @@ -3,13 +3,26 @@ const kotlinCompiler = require('@jetbrains/kotlinc-js-api'); const globby = require('globby'); const fs = require('fs-extra'); const path = require('path'); +const log = require('webpack-log'); const DCEPlugin = require('./dce-plugin'); +const librariesLookup = require('./libraries-lookup'); +function getDefaultPackagesContents() { + try { + return [require(path.resolve(process.cwd(), 'package.json'))]; + } catch (e) { + return []; + } +} + +const pluginName = 'Kotlin Plugin'; const DEFAULT_OPTIONS = { src: null, // An array or string with sources path output: 'kotlin_build', moduleName: 'kotlinApp', libraries: [], + librariesAutoLookup: false, + packagesContents: getDefaultPackagesContents(), verbose: false, sourceMaps: true, sourceMapEmbedSources: 'always', @@ -19,161 +32,226 @@ const DEFAULT_OPTIONS = { class KotlinWebpackPlugin { constructor(options) { + const logLevel = !options.verbose ? 'silent' : 'info'; + this.log = log({ name: pluginName, level: logLevel }); + const opts = Object.assign({}, DEFAULT_OPTIONS, options); - this.librariesMainFiles = opts.libraries; - this.options = Object.assign({}, opts, { - libraries: opts.libraries.map(main => - main.replace(/(?:\.js)?$/, '.meta.js') - ), - }); + this.prepareLibraries = this.prepareLibraries.bind(this); + this.options = this.prepareLibraries(opts); + this.outputPath = path.resolve( `${this.options.output}/${this.options.moduleName}.js` ); + this.firstCompilationError = null; - this.compileIfKotlinFilesChanged = this.compileIfKotlinFilesChanged.bind( - this - ); + this.compileIfKotlinFilesChanged = + this.compileIfKotlinFilesChanged.bind(this); this.watchKotlinSources = this.watchKotlinSources.bind(this); this.compileIfFirstRun = this.compileIfFirstRun.bind(this); + this.reportFirstCompilationError = + this.reportFirstCompilationError.bind(this); this.optimizeDeadCode = this.optimizeDeadCode.bind(this); this.setPastDate = this.setPastDate.bind(this); this.startTime = Date.now(); - this.prevTimestamps = {}; + this.prevTimestamps = new Map(); this.initialRun = true; this.sources = [].concat(this.options.src); } - log(...args) { - if (this.options.verbose) { - console.info('>>> Kotlin Plugin: >>>', ...args); - } + apply(compiler) { + compiler.hooks.beforeCompile.tapAsync(pluginName, this.compileIfFirstRun); + compiler.hooks.compilation.tap( + pluginName, + this.reportFirstCompilationError + ); + compiler.hooks.make.tapAsync(pluginName, this.compileIfKotlinFilesChanged); + compiler.hooks.emit.tapAsync(pluginName, this.watchKotlinSources); } - apply(compiler) { - compiler.plugin('before-compile', this.compileIfFirstRun); - compiler.plugin('make', this.compileIfKotlinFilesChanged); - compiler.plugin('emit', this.watchKotlinSources); + prepareLibraries(opts) { + if (opts.librariesAutoLookup) { + if (opts.libraries.length > 0) { + this.log.warn( + '"libraries" option is ignored because "librariesAutoLookup" option is enabled' + ); + } + + opts.libraries = librariesLookup.lookupKotlinLibraries( + opts.packagesContents + ); + + this.log.info( + `Autolookup found the following Kotlin libs: + ${opts.libraries.join('\n')}` + ); + } + + return Object.assign({}, opts, { + libraries: opts.libraries.map((main) => + main.replace(/(?:\.js)?$/, '.meta.js') + ), + librariesMainFiles: opts.libraries, + }); } copyLibraries() { - const files = this.librariesMainFiles.concat( - this.librariesMainFiles.map(main => `${main}.map`) + const files = this.options.librariesMainFiles.concat( + this.options.librariesMainFiles.map((main) => `${main}.map`) ); return Promise.all( - files.map(file => + files.map((file) => fs.copy(file, path.join(this.options.output, path.basename(file))) ) ); } - compileIfKotlinFilesChanged(compilation, done) { - const changedFiles = Object.keys(compilation.fileTimestamps).filter( - watchfile => - (this.prevTimestamps[watchfile] || this.startTime) < - (compilation.fileTimestamps[watchfile] || Infinity) + async compileIfKotlinFilesChanged(compilation, done) { + const changedFiles = Array.from(compilation.fileTimestamps.keys()).filter( + (watchfile) => + (this.prevTimestamps.get(watchfile) || this.startTime) < + (compilation.fileTimestamps.get(watchfile) || Infinity) ); this.prevTimestamps = compilation.fileTimestamps; - if (!changedFiles.some(it => /\.kt$/.test(it))) { + if (!changedFiles.some((it) => /\.kt$/.test(it))) { done(); return; } - this.log( + this.log.info( `Compiling Kotlin sources because the following files were changed: ${changedFiles.join( ', ' )}` ); - this.compileKotlinSources() - .then(done) - .catch(err => { - compilation.errors.push(err); - done(); - }); + + try { + await this.compileKotlinSources(); + } catch (e) { + compilation.errors.push(e); + } finally { + done(); + } } - compileKotlinSources() { - return kotlinCompiler - .compile( - Object.assign({}, this.options, { - output: this.outputPath, - sources: this.sources, - moduleKind: 'commonjs', - noWarn: true, - verbose: false, - }) - ) - .then(() => { - if (this.options.optimize) { - return this.optimizeDeadCode(); - } - }); + async compileKotlinSources() { + await kotlinCompiler.compile( + Object.assign({}, this.options, { + output: this.outputPath, + sources: this.sources, + moduleKind: 'commonjs', + noWarn: true, + verbose: false, + }) + ); + + if (this.options.optimize) { + return this.optimizeDeadCode(); + } } - watchKotlinSources(compilation, done) { - const patterns = this.sources.map(it => it + '/**/*.kt'); - globby(patterns, { + async watchKotlinSources(compilation, done) { + const patterns = this.sources.map((it) => `${it}/**/*.kt`); + const paths = await globby(patterns, { absolute: true, - }).then(paths => { - const normalizedPaths = paths.map(it => path.normalize(it)); - compilation.fileDependencies.push(...normalizedPaths); - done(); }); + + const normalizedPaths = paths.map((it) => path.normalize(it)); + + if (compilation.fileDependencies.add) { + for (const path of normalizedPaths) { + compilation.fileDependencies.add(path); + } + } else { + // Before Webpack 4 - fileDepenencies was an array + for (const path of normalizedPaths) { + compilation.fileDependencies.push(path); + } + } + + done(); } - compileIfFirstRun(compilationParams, done) { + async compileIfFirstRun(params, done) { if (!this.initialRun) { - done(); - return; + return done(); } this.initialRun = false; - this.log('Initial compilation of Kotlin sources...'); - this.compileKotlinSources() - .then(() => { - if (!this.options.optimize) { - return this.copyLibraries(); - } - }) - .then(this.setPastDate) - .then(done, done); + this.log.info('Initial compilation of Kotlin sources...'); + + try { + await this.compileKotlinSources(); + + if (!this.options.optimize) { + await Promise.all([ + fs.remove(path.join(this.options.output, 'kotlin.js')), + this.copyLibraries(), + ]); + } + + await this.setPastDate(); + } catch (e) { + this.generateErrorBundle(e.toString()); + this.firstCompilationError = e; + } finally { + done(); + } + } + + reportFirstCompilationError(compilation) { + if (this.firstCompilationError) { + compilation.errors.push(this.firstCompilationError); + this.firstCompilationError = null; + } } optimizeDeadCode() { - this.log(`Optimizing Kotlin runtime...`); + this.log.info( + `Optimizing Kotlin runtime... \nLibraries:`, + this.options.librariesMainFiles.join('\n') + ); + return DCEPlugin.optimize({ + moduleName: this.options.moduleName, outputDir: this.options.output, outputPath: this.outputPath, - librariesPaths: [].concat(this.librariesMainFiles), + librariesPaths: [].concat(this.options.librariesMainFiles), }); } - setPastDate() { - //Hack around multiple recompilations on start: set past modify date + async setPastDate() { + // Hack around multiple recompilations on start: set past modify date const timestamp = 100; const output = this.options.output; - return ( - fs - .readdir(output) - .then(files => - Promise.all( - files.map(file => { - return fs.utimes( - path.resolve(output, file), - timestamp, - timestamp - ); - }) - ) - ) - // discard the value - .then(() => {}) + const files = await fs.readdir(output); + await Promise.all( + files.map((file) => + fs.utimes(path.resolve(output, file), timestamp, timestamp) + ) ); } + + generateErrorBundle(errorMessage) { + const file = path.join( + this.options.output, + `${this.options.moduleName}.js` + ); + + this.log.info('Generating error entry', file); + + if (!fs.existsSync(this.options.output)) { + fs.mkdirSync(this.options.output, { recursive: true }); + } + + const message = `throw new Error("Failed to compile Kotlin code: ${( + errorMessage || '' + ).replace(/\n/g, ' ')}")`; + fs.writeFileSync(file, message); + } } module.exports = KotlinWebpackPlugin; diff --git a/packages/kotlinc-js-api/.nvmrc b/packages/kotlinc-js-api/.nvmrc new file mode 100644 index 00000000..ca4a60d1 --- /dev/null +++ b/packages/kotlinc-js-api/.nvmrc @@ -0,0 +1 @@ +v14.18.2 diff --git a/packages/kotlinc-js-api/kotlin-compiler.js b/packages/kotlinc-js-api/kotlin-compiler.js index 7728a3f7..d0b26d70 100644 --- a/packages/kotlinc-js-api/kotlin-compiler.js +++ b/packages/kotlinc-js-api/kotlin-compiler.js @@ -1,9 +1,13 @@ 'use strict'; const spawn = require('cross-spawn').spawn; const isWindows = /^win/.test(process.platform); +const SUCCESS_CODE = 0; -function addOptionWithValue(options, optionName, optionValue) { +function addOptionWithValue(options, optionName, optionValue, useEqual) { if (optionValue) { + if (useEqual) { + return options.concat(`${optionName}=${optionValue}`); + } return options.concat(optionName, optionValue); } return options; @@ -48,6 +52,12 @@ function convertOptionsIntoArguments(options) { '-module-kind', options.moduleKind ); + argumentsList = addOptionWithValue( + argumentsList, + '-Xplugin', + options.plugin, + true + ); if (options.libraries && options.libraries.length) { argumentsList = argumentsList.concat( @@ -60,11 +70,16 @@ function convertOptionsIntoArguments(options) { if (options.experimental.multiPlatform) { argumentsList = argumentsList.concat('-Xmulti-platform'); } + if (options.experimental.customArguments) { + argumentsList = argumentsList.concat( + options.experimental.customArguments + ); + } } argumentsList = argumentsList.concat(options.sources); - return argumentsList.filter(arg => !!arg); + return argumentsList.filter((arg) => !!arg); } function compile(options) { @@ -76,26 +91,27 @@ function compile(options) { convertOptionsIntoArguments(options), { stdio: [process.stdin, process.stdout, 'pipe'] } ); - let hasErrors = false; let errors = ''; - compilation.stderr.on('data', data => { - hasErrors = true; + compilation.stderr.on('data', (data) => { errors += data.toString(); }); - compilation.on('error', err => { - hasErrors = true; + compilation.on('error', (err) => { errors += 'kotlin-js failed. Do you have Kotlin installed?'; errors += JSON.stringify(err); }); - compilation.on('close', () => { - if (hasErrors === false) { - resolve(); - } else { - reject(errors); + compilation.on('close', (code) => { + if (code !== SUCCESS_CODE) { + reject(errors || `Kotlin compiler exited with code ${code}`); + return; + } + + if (errors) { + console.warn('Kotlin Compiler stderr output:', errors); } + resolve(); }); }); } diff --git a/packages/kotlinc-js-api/package.json b/packages/kotlinc-js-api/package.json index f9c03792..61679366 100644 --- a/packages/kotlinc-js-api/package.json +++ b/packages/kotlinc-js-api/package.json @@ -1,6 +1,6 @@ { "name": "@jetbrains/kotlinc-js-api", - "version": "1.2.3", + "version": "2.0.1", "description": "KotlincJS compiler wrapper for NodeJS", "main": "kotlin-compiler.js", "scripts": { @@ -8,7 +8,7 @@ }, "repository": "JetBrains/create-react-kotlin-app", "engines": { - "node": ">=6" + "node": ">=14.18.2" }, "files": [ "compiler", @@ -23,7 +23,7 @@ "author": "Andrey Skladchikov ", "license": "Apache-2.0", "dependencies": { - "cross-spawn": "^6.0.0", - "kotlin-compiler": "^1.2.1" + "cross-spawn": "^7.0.3", + "kotlin-compiler": "^1.3.61" } } diff --git a/packages/kotlinc-js-api/test/kotlin-compiler.test.js b/packages/kotlinc-js-api/test/kotlin-compiler.test.js index 78c0de08..ae934e04 100644 --- a/packages/kotlinc-js-api/test/kotlin-compiler.test.js +++ b/packages/kotlinc-js-api/test/kotlin-compiler.test.js @@ -12,20 +12,22 @@ kotlinCompiler sources: [__dirname], sourceMaps: true, moduleKind: 'commonjs', - libraries: [ - '@jetbrains/kotlin-extensions', - '@jetbrains/kotlin-react', - ].map(lib => require.resolve(lib).replace(/(?:\.js)?$/, '.meta.js')), + plugin: require.resolve( + `kotlin-compiler/lib/kotlinx-serialization-compiler-plugin.jar` + ), + libraries: ['@jetbrains/kotlin-extensions', '@jetbrains/kotlin-react'].map( + (lib) => require.resolve(lib).replace(/(?:\.js)?$/, '.meta.js') + ), }) .then(() => { - return new Promise(resolve => + return new Promise((resolve) => fs.readFile(DIST_FILE_PATH, (error, data) => resolve(data)) ); }) - .then(compiledFileContent => { - return new Promise(resolve => + .then((compiledFileContent) => { + return new Promise((resolve) => fs.readFile(REFERENCE_PATH, (error, data) => resolve(data)) - ).then(reference => ({ + ).then((reference) => ({ compiledFileContent, reference, })); @@ -39,4 +41,8 @@ kotlinCompiler } else { console.info('Test passed'); } + }) + .catch((err) => { + console.error('kotlinc-js-api test failed:', err); + process.exit(1); }); diff --git a/packages/kotlinc-js-api/test/reference.js.ref b/packages/kotlinc-js-api/test/reference.js.ref index 9d29b77e..b9a201e7 100644 --- a/packages/kotlinc-js-api/test/reference.js.ref +++ b/packages/kotlinc-js-api/test/reference.js.ref @@ -1,10 +1,11 @@ -(function (_, Kotlin, $module$react, $module$kotlin_extensions) { +(function (_, Kotlin, $module$kotlin_extensions, $module$react) { 'use strict'; var $$importsForInline$$ = _.$$importsForInline$$ || (_.$$importsForInline$$ = {}); + var createElement = $module$react.createElement; var println = Kotlin.kotlin.io.println_s8jyv4$; function main(args) { var obj = {}; - var el = $module$react.createElement('test', obj, 'test'); + var el = createElement('test', obj, 'test'); println(JSON.stringify(el)); } $$importsForInline$$['kotlin-extensions'] = $module$kotlin_extensions; @@ -13,6 +14,6 @@ main([]); Kotlin.defineModule('dist', _); return _; -}(module.exports, require('kotlin'), require('react'), require('kotlin-extensions'))); +}(module.exports, require('kotlin'), require('kotlin-extensions'), require('react'))); //# sourceMappingURL=dist.js.map diff --git a/packages/kotlinc-js-api/test/test-source.kt b/packages/kotlinc-js-api/test/test-source.kt index e3525452..13fa79bc 100644 --- a/packages/kotlinc-js-api/test/test-source.kt +++ b/packages/kotlinc-js-api/test/test-source.kt @@ -4,6 +4,6 @@ import kotlinext.js.* import react.* fun main(args: Array) { - val el = React.createElement("test", js {}, "test") + val el = createElement("test", js {}, "test") println(JSON.stringify(el)) } diff --git a/packages/react-scripts/.nvmrc b/packages/react-scripts/.nvmrc new file mode 100644 index 00000000..ca4a60d1 --- /dev/null +++ b/packages/react-scripts/.nvmrc @@ -0,0 +1 @@ +v14.18.2 diff --git a/packages/react-scripts/config/env.js b/packages/react-scripts/config/env.js index fa42747f..7c5bb8f7 100644 --- a/packages/react-scripts/config/env.js +++ b/packages/react-scripts/config/env.js @@ -37,7 +37,7 @@ var dotenvFiles = [ // if this file is missing. dotenv will never modify any environment variables // that have already been set. // https://github.com/motdotla/dotenv -dotenvFiles.forEach(dotenvFile => { +dotenvFiles.forEach((dotenvFile) => { if (fs.existsSync(dotenvFile)) { require('dotenv').config({ path: dotenvFile, @@ -57,8 +57,8 @@ dotenvFiles.forEach(dotenvFile => { const appDirectory = fs.realpathSync(process.cwd()); process.env.NODE_PATH = (process.env.NODE_PATH || '') .split(path.delimiter) - .filter(folder => folder && !path.isAbsolute(folder)) - .map(folder => path.resolve(appDirectory, folder)) + .filter((folder) => folder && !path.isAbsolute(folder)) + .map((folder) => path.resolve(appDirectory, folder)) .join(path.delimiter); // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be @@ -67,7 +67,7 @@ const REACT_APP = /^REACT_APP_/i; function getClientEnvironment(publicUrl) { const raw = Object.keys(process.env) - .filter(key => REACT_APP.test(key)) + .filter((key) => REACT_APP.test(key)) .reduce( (env, key) => { env[key] = process.env[key]; diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 8800e5ad..63e96724 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -15,7 +15,7 @@ const url = require('url'); // Make sure any symlinks in the project folder are resolved: // https://github.com/facebookincubator/create-react-app/issues/637 const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = relativePath => path.resolve(appDirectory, relativePath); +const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); const envPublicUrl = process.env.PUBLIC_URL; @@ -30,7 +30,7 @@ function ensureSlash(path, needsSlash) { } } -const getPublicUrl = appPackageJson => +const getPublicUrl = (appPackageJson) => envPublicUrl || require(appPackageJson).homepage; // We use `PUBLIC_URL` environment variable or "homepage" field to infer @@ -63,7 +63,8 @@ module.exports = { }; // @remove-on-eject-begin -const resolveOwn = relativePath => path.resolve(__dirname, '..', relativePath); +const resolveOwn = (relativePath) => + path.resolve(__dirname, '..', relativePath); // config before eject: we're in ./node_modules/react-scripts/config/ module.exports = { @@ -82,6 +83,7 @@ module.exports = { projectPath: resolveApp('.'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), + ownPackageJson: resolveOwn('package.json'), ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3 }; @@ -112,6 +114,7 @@ if ( projectPath: resolveOwn('../..'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), + ownPackageJson: resolveOwn('package.json'), ownNodeModules: resolveOwn('node_modules'), }; } diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index a7bb8978..0bf47caa 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -76,7 +76,7 @@ module.exports = { // This is the URL that app is served from. We use "/" in development. publicPath: publicPath, // Point sourcemap entries to original disk location - devtoolModuleFilenameTemplate: info => + devtoolModuleFilenameTemplate: (info) => path.resolve(info.absoluteResourcePath), }, resolve: { @@ -85,9 +85,9 @@ module.exports = { // if there are any conflicts. This matches Node resolution mechanism. // https://github.com/facebookincubator/create-react-app/issues/253 modules: [ - paths.kotlinOutputPath, 'node_modules', paths.appNodeModules, + paths.kotlinOutputPath, ].concat( // It is guaranteed to exist because we tweak it in `env.js` process.env.NODE_PATH.split(path.delimiter).filter(Boolean) @@ -173,12 +173,6 @@ module.exports = { plugins: () => [ require('postcss-flexbugs-fixes'), autoprefixer({ - browsers: [ - '>1%', - 'last 4 versions', - 'Firefox ESR', - 'not ie < 9', // React doesn't support IE8 anyway - ], flexbox: 'no-2009', }), ], @@ -195,23 +189,24 @@ module.exports = { src: paths.appSrc, output: paths.kotlinOutputPath, moduleName: kotlinModuleName, - libraries: [ - '@jetbrains/kotlin-extensions', - '@jetbrains/kotlin-react', - '@jetbrains/kotlin-react-dom', - 'kotlinx-html', - ].map(pkg => require.resolve(pkg)), + librariesAutoLookup: true, + packagesContents: [ + // @remove-on-eject-begin + require(paths.ownPackageJson), + // @remove-on-eject-end + require(paths.appPackageJson), + ], }), - // Makes some environment variables available in index.html. - // The public URL is available as %PUBLIC_URL% in index.html, e.g.: - // - // In development, this will be an empty string. - new InterpolateHtmlPlugin(env.raw), // Generates an `index.html` file with the