diff --git a/README.md b/README.md index 7b48e6f..4b33fcf 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ To get started with Treats, you can simply do the following: You don't need to configure webpack, babel, or any other build tools by yourself ## What's in the box? -1. React, JSX, ES6, and Flow syntax support (TypeScript support is coming!). +1. React, JSX, ES6, and Flow (or TypeScript) syntax support. 2. Preconfigured Redux, GraphQL client and i18n out-of-the-box. *(You can disable Redux/GraphQL client if you're not using it, it'll only leave minimum trace in your build)* 3. Server-side rendering, code-splitting and hot-module replacement configured out-of-the-box. 4. CSS Modules support with CSS, LESS, or SASS syntax with autoprefixer, or use any CSS-in-JS library that you like! diff --git a/docusaurus/docs/main-concept/generator.md b/docusaurus/docs/main-concept/generator.md index 17ee771..57d628a 100644 --- a/docusaurus/docs/main-concept/generator.md +++ b/docusaurus/docs/main-concept/generator.md @@ -25,6 +25,8 @@ There's several built-in generator that you can use: 4. `helper` -  Generates Treats helper object boilerplates. 5. `middleware` -  Generates Treats middleware object boilerplates. +We also provide option to create a Typescript template. To generate Typescript templates choose `true (t)` when prompted about Typescript usage. + For more information about how to create your own template you can find it [here][authoring-addons-generators] [authoring-addons-generators]: ../authoring-addons/generator.html diff --git a/docusaurus/docs/main-concept/typescript.md b/docusaurus/docs/main-concept/typescript.md new file mode 100644 index 0000000..ce3e5f2 --- /dev/null +++ b/docusaurus/docs/main-concept/typescript.md @@ -0,0 +1,67 @@ +--- +id: typescript +title: Working with Typescript +sidebar_label: Typescript +--- +Treats also provide Typescript support. If you write your projects in Typescript, Treats will recognize the syntax and render your component. We provide support both in our `create-treats-app` and `treats` commands. + +"How Treats recognize our projects as a Typescript projects?" + +Good question. Treats will recognize your projects as a Typescript projects when you provide `.ts or .tsx` in your projects root. Therefore, **please be aware when it is necessary to add `.(ts|tsx) files` into your projects**. + +### Create Your First Typescript Treats App +To start Typescript Treats project, simply choose `true (t)` when prompted about Typescript usage on `create-treats-app` command. + +``` + Treats > Welcome to Treats! Let's setup your app, shall we? +prompt: Application name: (my-ts-treats-app) +prompt: Application version: (0.0.1) +prompt: Application description: (My First Treats App in Typescript) +prompt: Do you want to use Typescript? (true (t)|false (f)): (false) +``` + +After you finish fill the prompt, Treats will install the dependencies for you. So get some tea for you first and rest for a bit :) + +Finished! Congratulations your first Treats app in Typescript is already generated. To start the projects, type `yarn start` or `npm start` + +``` +cd +yarn start +``` + +### Typescript Generator +As written in [Generator][main-concept-generator], to generate Typescript built-in template (component, redux, test, helper, and middleware), simply choose `true (t)` when prompted about Typescript usage. + +### Typescript Config +As we know, Typescript projects require `tsconfig.json`. We also understand that some of its configurations redundant with our `treats.config.(js|ts)`. Therefore, we create a Typescript handler in our `treats.config.(js|ts)`. This will make our `tsconfig.json` a generated file, which means: __"Please do not change config in tsconfig.json. Make your change in treats.config.(js|ts) instead"__. + +The Typescript field content will be the same as `tsconfig.json`, so please check the [docs][tsconfig-docs], if you want to customize one. Nothing to fear if you don't want to customize one, we have default config and will generate it for you the moment you `start` or `build` your projects. + +Here's some example of `treats.config.(js|ts)`: + +``` +// treats.config.(js|ts) +... +const config = { + ..., + + typescript: { + ..., + "compilerOptions": { + ..., + target: "es5", + paths: { + someAlias: [ + "./path/to/alias" + ] + } + } + } +}; + +module.exports = config; +``` + + +[main-concept-generator]: ./generator.html +[tsconfig-docs]: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html diff --git a/docusaurus/website/sidebars.json b/docusaurus/website/sidebars.json index 20a766e..ccafa02 100644 --- a/docusaurus/website/sidebars.json +++ b/docusaurus/website/sidebars.json @@ -24,7 +24,8 @@ "main-concept/environment-variable", "main-concept/generator", "main-concept/scripts", - "main-concept/addons" + "main-concept/addons", + "main-concept/typescript" ], "API Reference": [ "api-reference/overview", diff --git a/example/typescript-app/.gitignore b/example/typescript-app/.gitignore new file mode 100644 index 0000000..223e501 --- /dev/null +++ b/example/typescript-app/.gitignore @@ -0,0 +1,15 @@ +node_modules +yarn.lock +yarn-error.log +package-lock.json +.env +.arcrc +dist +public +coverage +storybook-static +stats +profile +packages/**/*.md +**/*.DS_Store +.cache-loader diff --git a/example/typescript-app/package.json b/example/typescript-app/package.json new file mode 100644 index 0000000..3995377 --- /dev/null +++ b/example/typescript-app/package.json @@ -0,0 +1,38 @@ +{ + "name": "typescript-app", + "version": "0.0.1", + "description": "My First Treats App with Typescript Language!", + "license": "ISC", + "scripts": { + "start": "treats start", + "build:client": "treats build --target client", + "build:server": "treats build --target server", + "build": "treats build", + "clean": "treats clean", + "generate": "treats generate", + "analyze:client": "treats build --target client --analyze", + "analyze:server": "treats build --target server --analyze", + "profile": "yarn build:server && node --prof dist/server.js", + "documentation:build": "treats documentation build src/", + "documentation:lint": "treats documentation lint src/", + "documentation:phriction": "treats documentation export src/ --target phriction", + "documentation:flush": "treats documentation flush src/", + "test": "treats test", + "test:watch": "treats test --watchAll", + "test:coverage": "treats test --coverage" + }, + "dependencies": { + "treats": "0.1.1", + "typescript": "3.2.2", + "@types/enzyme": "3.1.15", + "@types/jest": "23.3.10", + "@types/node": "10.12.15", + "@types/react": "16.7.17", + "@types/react-dom": "16.0.11", + "@types/react-helmet": "5.0.7", + "@types/react-intl": "2.3.14", + "@types/react-redux": "6.0.11", + "@types/react-router-dom": "4.3.1", + "@types/redux": "3.6.0" + } +} diff --git a/example/typescript-app/src/_locale/en.json b/example/typescript-app/src/_locale/en.json new file mode 100644 index 0000000..2712f04 --- /dev/null +++ b/example/typescript-app/src/_locale/en.json @@ -0,0 +1,4 @@ +{ + "welcome_page__description1": "A development kit to make your experience on building fully customizable {React} app with built-in Server-side rendering, Code-splitting, i18n, {Redux} and {GraphQL} sweeter!", + "welcome_page__description2": "To get started, edit {Source} and save to reload, or learn more on our {Documentation}" +} diff --git a/example/typescript-app/src/_locale/id.json b/example/typescript-app/src/_locale/id.json new file mode 100644 index 0000000..789d228 --- /dev/null +++ b/example/typescript-app/src/_locale/id.json @@ -0,0 +1,4 @@ +{ + "welcome_page__description1": "Sebuah development kit untuk membuat pengalaman anda dalam membangun sebuah aplikasi {React} yang sangat mudah dikustomisasi dengan Server-side rendering, Code-splitting, i18n, {Redux} dan {GraphQL} jadi lebih manis!", + "welcome_page__description2": "Untuk memulai, sunting {Source} dan simpan untuk me-reload, atau pelajari lebih lanjut di {Documentation} kami." +} diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_locale/index.js b/example/typescript-app/src/_locale/index.ts similarity index 100% rename from packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_locale/index.js rename to example/typescript-app/src/_locale/index.ts diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/module.js b/example/typescript-app/src/_route/module.ts similarity index 100% rename from packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/module.js rename to example/typescript-app/src/_route/module.ts diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/path.js b/example/typescript-app/src/_route/path.ts similarity index 100% rename from packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/path.js rename to example/typescript-app/src/_route/path.ts diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/route.js b/example/typescript-app/src/_route/route.ts similarity index 100% rename from packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/route.js rename to example/typescript-app/src/_route/route.ts diff --git a/example/typescript-app/src/lib/treats.d.ts b/example/typescript-app/src/lib/treats.d.ts new file mode 100644 index 0000000..aa22baf --- /dev/null +++ b/example/typescript-app/src/lib/treats.d.ts @@ -0,0 +1 @@ +/// diff --git a/example/typescript-app/src/page/welcome/NotoSans-Bold.ttf b/example/typescript-app/src/page/welcome/NotoSans-Bold.ttf new file mode 100644 index 0000000..1db7886 Binary files /dev/null and b/example/typescript-app/src/page/welcome/NotoSans-Bold.ttf differ diff --git a/example/typescript-app/src/page/welcome/NotoSans-Regular.ttf b/example/typescript-app/src/page/welcome/NotoSans-Regular.ttf new file mode 100644 index 0000000..0a01a06 Binary files /dev/null and b/example/typescript-app/src/page/welcome/NotoSans-Regular.ttf differ diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/index.js b/example/typescript-app/src/page/welcome/index.tsx similarity index 100% rename from packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/index.js rename to example/typescript-app/src/page/welcome/index.tsx diff --git a/example/typescript-app/src/page/welcome/treats.png b/example/typescript-app/src/page/welcome/treats.png new file mode 100644 index 0000000..bc3b5f2 Binary files /dev/null and b/example/typescript-app/src/page/welcome/treats.png differ diff --git a/example/typescript-app/src/page/welcome/welcome.css b/example/typescript-app/src/page/welcome/welcome.css new file mode 100644 index 0000000..ee9943c --- /dev/null +++ b/example/typescript-app/src/page/welcome/welcome.css @@ -0,0 +1,88 @@ +@font-face { + font-family: "Noto Sans"; + src: url("./NotoSans-Bold.ttf"); + font-weight: bold; +} +@font-face { + font-family: "Noto Sans"; + src: url("./NotoSans-Regular.ttf"); + font-weight: normal; +} + +a { + color: #42b549; + text-decoration: none; +} + +a:hover { + color: #ff5722; +} + +.welcome_page { + position: relative; + display: block; + font-family: "Noto Sans", sans-serif; + text-align: center; + height: 700px; + white-space: nowrap; + padding: 0 30px; +} + +.welcome_page:before { + content: ""; + display: inline-block; + vertical-align: middle; + height: 100%; + width: 0; +} + +.welcome_page__content { + display: inline-block; + vertical-align: middle; + white-space: normal; + width: 100%; +} + +.welcome_page__toped { + width: 200px; +} +.welcome_page__locale_switcher_container { + position: relative; + white-space: nowrap; + padding-top: 20px; + font-size: 12px; +} + +.welcome_page__locale_switcher { + display: inline-block; + vertical-align: middle; + padding: 10px; + min-width: 100px; + background: #fff; + color: #42b549; + border: 1px solid #f0f0f0; +} + +.welcome_page__locale_switcher:hover { + color: #42b549; + background: #EEE; +} + +.welcome_page__locale_switcher:global(.active) { + background: #42b549; + color: #fff; +} + +.welcome_page__locale_switcher:first-child { + border-top-left-radius: 30px; + border-bottom-left-radius: 30px; +} + +.welcome_page__locale_switcher:last-child { + border-top-right-radius: 30px; + border-bottom-right-radius: 30px; +} + +.welcome_page__locale_switcher:global(.active):hover { + color: #FFF; +} diff --git a/example/typescript-app/src/page/welcome/welcome.tsx b/example/typescript-app/src/page/welcome/welcome.tsx new file mode 100644 index 0000000..e74b906 --- /dev/null +++ b/example/typescript-app/src/page/welcome/welcome.tsx @@ -0,0 +1,89 @@ +import React from "react"; +import Helmet from "@treats/helmet"; +import { FormattedMessage, injectIntl, InjectedIntlProps } from "@treats/intl"; +import AsyncComponent from "@treats/component/async-component"; + +import style from "./welcome.css"; +import treats from "./treats.png"; + +/** + * Welcome to treats component + * + * NOTE: + * If you have dependencies error: + * "Could not find declaration file for @treats/..." + * It means your treats doesn't support typescript yet. + * Please update it to the latest version + * + * @param props React props + * @param props.intl Intl Object + * @author Tokopedia Engineering + */ +const Welcome = ({ intl }: InjectedIntlProps) => ( +
+ + Welcome to Treats! + +
+ Treats +

Welcome, let's have some treats!

+ + React + + ), + Redux: ( + + Redux + + ), + GraphQL: ( + + GraphQL + + ) + }} + /> +

+ src/page/welcome.js, + Documentation: ( + + documentation + + ) + }} + /> +

+ +
+
+); + +export default AsyncComponent(module, injectIntl(Welcome)); diff --git a/example/typescript-app/treats.config.js b/example/typescript-app/treats.config.js new file mode 100644 index 0000000..1716b8f --- /dev/null +++ b/example/typescript-app/treats.config.js @@ -0,0 +1,13 @@ +const path = require("path"); + +const config = { + app: { + name: "typescript-app", + slug: "typescript-app" + }, + alias: { + "@page": path.resolve(__dirname, "./src/page") + } +}; + +module.exports = config; diff --git a/example/typescript-app/tsconfig.json b/example/typescript-app/tsconfig.json new file mode 100644 index 0000000..6987221 --- /dev/null +++ b/example/typescript-app/tsconfig.json @@ -0,0 +1,69 @@ +{ + "compilerOptions": { + "target": "es5", + "allowJs": true, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "outDir": "./dist/", + "esModuleInterop": true, + "lib": [ + "esnext", + "dom" + ], + "baseUrl": ".", + "paths": { + "@treats/server": [ + "./node_modules/treats/server" + ], + "@treats/client": [ + "./node_modules/treats/client" + ], + "@treats/component": [ + "./node_modules/treats/shared/component" + ], + "@treats/util": [ + "./node_modules/treats/shared/util" + ], + "@treats/route": [ + "./node_modules/treats/shared/route" + ], + "@treats/alias": [ + "./node_modules/treats/shared/alias" + ], + "@treats/redux": [ + "./node_modules/treats/shared/proxy/redux.js" + ], + "@treats/router": [ + "./node_modules/treats/shared/proxy/router.js" + ], + "@treats/intl": [ + "./node_modules/react-intl" + ], + "@treats/helmet": [ + "./node_modules/react-helmet" + ], + "@treats/graphql": [ + "./node_modules/react-apollo" + ], + "@treats/locale-data": [ + "./node_modules/react-intl/locale-data" + ], + "@page/*": [ + "./src/page/*" + ] + } + }, + "include": [ + "src" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index da92dd7..6345ea2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -36,7 +36,6 @@ module.exports = { coveragePathIgnorePatterns: ["node_modules/", "generator/"], collectCoverage: true, collectCoverageFrom: ["/**/*.{js}", "!/**/*.stories.js"], - coveragePathIgnorePatterns: ["node_modules/", "generator/"], coverageReporters: ["html"], coverageThreshold }; diff --git a/packages/create-treats-app/README.md b/packages/create-treats-app/README.md index 6768715..8709b30 100644 --- a/packages/create-treats-app/README.md +++ b/packages/create-treats-app/README.md @@ -15,7 +15,7 @@ To get started with Treats, you can simply do the following: You don't need to configure webpack, babel, or any other build tools by yourself ## What's in the box? -1. React, JSX, ES6, and Flow syntax support (TypeScript support is coming!). +1. React, JSX, ES6, and Flow (or TypeScript) syntax support. 2. Preconfigured Redux, GraphQL client and i18n out-of-the-box. *(You can disable Redux/GraphQL client if you're not using it, it'll only leave minimum trace in your build)* 3. Server-side rendering, code-splitting and hot-module replacement configured out-of-the-box. 4. CSS Modules support with CSS, LESS, or SASS syntax with autoprefixer, or use any CSS-in-JS library that you like! diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/.gitignore b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/.gitignore index 7a5f054..223e501 100644 --- a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/.gitignore +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/.gitignore @@ -12,3 +12,4 @@ stats profile packages/**/*.md **/*.DS_Store +.cache-loader diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/<%if(USE_TYPESCRIPT)%>tsconfig.json<%endif%> b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/<%if(USE_TYPESCRIPT)%>tsconfig.json<%endif%> new file mode 100644 index 0000000..3e1de74 --- /dev/null +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/<%if(USE_TYPESCRIPT)%>tsconfig.json<%endif%> @@ -0,0 +1,66 @@ +{ + "compilerOptions": { + "target": "es5", + "allowJs": true, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "outDir": "./dist/", + "esModuleInterop": true, + "lib": [ + "esnext", + "dom" + ], + "baseUrl": ".", + "paths": { + "@treats/server": [ + "./node_modules/treats/server" + ], + "@treats/client": [ + "./node_modules/treats/client" + ], + "@treats/component": [ + "./node_modules/treats/shared/component" + ], + "@treats/util": [ + "./node_modules/treats/shared/util" + ], + "@treats/route": [ + "./node_modules/treats/shared/route" + ], + "@treats/alias": [ + "./node_modules/treats/shared/alias" + ], + "@treats/redux": [ + "./node_modules/treats/shared/proxy/redux.js" + ], + "@treats/router": [ + "./node_modules/treats/shared/proxy/router.js" + ], + "@treats/intl": [ + "./node_modules/react-intl" + ], + "@treats/helmet": [ + "./node_modules/react-helmet" + ], + "@treats/graphql": [ + "./node_modules/react-apollo" + ], + "@treats/locale-data": [ + "./node_modules/react-intl/locale-data" + ] + } + }, + "include": [ + "src" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/package.json b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/package.json index aa4bad5..78928ea 100644 --- a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/package.json +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/package.json @@ -22,6 +22,17 @@ "test:coverage": "treats test --coverage" }, "dependencies": { - "treats": "0.1.1" + "treats": "0.1.1<%if(USE_TYPESCRIPT)%>", + "typescript": "3.2.2", + "@types/enzyme": "3.1.15", + "@types/jest": "23.3.10", + "@types/node": "10.12.15", + "@types/react": "16.7.17", + "@types/react-dom": "16.0.11", + "@types/react-helmet": "5.0.7", + "@types/react-intl": "2.3.14", + "@types/react-redux": "6.0.11", + "@types/react-router-dom": "4.3.1", + "@types/redux": "3.6.0<%endif%>" } } diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/<%if(USE_TYPESCRIPT)%>lib<%endif%>/<%if(USE_TYPESCRIPT)%>treats.d.ts<%endif%> b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/<%if(USE_TYPESCRIPT)%>lib<%endif%>/<%if(USE_TYPESCRIPT)%>treats.d.ts<%endif%> new file mode 100644 index 0000000..aa22baf --- /dev/null +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/<%if(USE_TYPESCRIPT)%>lib<%endif%>/<%if(USE_TYPESCRIPT)%>treats.d.ts<%endif%> @@ -0,0 +1 @@ +/// diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_locale/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_locale/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> new file mode 100644 index 0000000..aaa9091 --- /dev/null +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_locale/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -0,0 +1,7 @@ +import en from "./en.json"; +import id from "./id.json"; + +export default { + en, + id +}; diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/module.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/module.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> new file mode 100644 index 0000000..6bf78f5 --- /dev/null +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/module.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -0,0 +1,9 @@ +import Welcome from "@page/welcome"; + +import { WELCOME } from "./path"; + +const module = { + [WELCOME]: Welcome +}; + +export default module; diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/path.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/path.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> new file mode 100644 index 0000000..de3c00c --- /dev/null +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/path.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -0,0 +1 @@ +export const WELCOME = "/"; diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/route.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/route.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> new file mode 100644 index 0000000..fda5c99 --- /dev/null +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/_route/route.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -0,0 +1,12 @@ +import { WELCOME } from "./path"; + +const route = [ + { + name: "welcome", + path: WELCOME, + exact: true, + disabled: true + } +]; + +export default route; diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/index.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/index.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> new file mode 100644 index 0000000..a2e0a68 --- /dev/null +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/index.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> @@ -0,0 +1,5 @@ +import AsyncLoader from "@treats/component/async-loader"; + +const Welcome = AsyncLoader({ component: import("./welcome") }); + +export default Welcome; diff --git a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/welcome.js b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/welcome.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> similarity index 93% rename from packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/welcome.js rename to packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/welcome.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> index 2e364b5..78b89e2 100644 --- a/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/welcome.js +++ b/packages/create-treats-app/generator/create-treats-app/<%APP_NAME%>/src/page/welcome/welcome.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> @@ -1,6 +1,6 @@ import React from "react"; import Helmet from "@treats/helmet"; -import { FormattedMessage, injectIntl } from "@treats/intl"; +import { FormattedMessage, injectIntl<%if(USE_TYPESCRIPT)%>, InjectedIntlProps<%endif%> } from "@treats/intl"; import AsyncComponent from "@treats/component/async-component"; import style from "./welcome.css"; @@ -12,7 +12,7 @@ import treats from "./treats.png"; * @param props.intl Intl Object * @author Tokopedia Engineering */ -const Welcome = ({ intl }) => ( +const Welcome = ({ intl }<%if(USE_TYPESCRIPT)%>: InjectedIntlProps<%endif%>) => (
Welcome to Treats! diff --git a/packages/create-treats-app/generator/create-treats-app/treats-generator.json b/packages/create-treats-app/generator/create-treats-app/treats-generator.json index 39ebdb8..483a20b 100644 --- a/packages/create-treats-app/generator/create-treats-app/treats-generator.json +++ b/packages/create-treats-app/generator/create-treats-app/treats-generator.json @@ -29,6 +29,12 @@ "description": "Application description", "default": "My First Treats App", "required": false + }, + "USE_TYPESCRIPT": { + "description": "Do you want to use Typescript?", + "type": "boolean", + "default": false, + "required": true } }, "after": [ diff --git a/packages/create-treats-app/index.js b/packages/create-treats-app/index.js index e4c0e7a..5e19d6c 100755 --- a/packages/create-treats-app/index.js +++ b/packages/create-treats-app/index.js @@ -14,5 +14,8 @@ const argv = require("yargs") " 🍰 Treats - Tokopedia React Development Kits, learn more on our documentation https://github.com/tokopedia/treats" ) .strict().argv; - -require("./scripts/generate")({ template: "create-treats-app", noconfig: true, ...argv }); + +require("./scripts/generate")({ + template: "create-treats-app", + noconfig: true, ...argv +}); diff --git a/packages/create-treats-app/scripts/generate b/packages/create-treats-app/scripts/generate index 3405366..f998999 100644 --- a/packages/create-treats-app/scripts/generate +++ b/packages/create-treats-app/scripts/generate @@ -37,6 +37,12 @@ const processFile = (filename, resultFileName, envVars) => { fs.copySync(filename, resultFileName); logger("debug", `Copied file ${resultFileName}`); } else { + const filenameComponents = filename.split("/"), + relativeFilename = filenameComponents[filenameComponents.length - 1]; + if (relativeFilename && templateParser(relativeFilename, envVars) === "") { + logger("debug", `Template ${filename} not generated`); + return true; + } logger("debug", `Found template text file ${filename}`); const templateDataDefault = fs.readFileSync(filename), finalDataDefault = templateParser(templateDataDefault.toString(), envVars); diff --git a/packages/treats/README.md b/packages/treats/README.md index 6768715..8709b30 100644 --- a/packages/treats/README.md +++ b/packages/treats/README.md @@ -15,7 +15,7 @@ To get started with Treats, you can simply do the following: You don't need to configure webpack, babel, or any other build tools by yourself ## What's in the box? -1. React, JSX, ES6, and Flow syntax support (TypeScript support is coming!). +1. React, JSX, ES6, and Flow (or TypeScript) syntax support. 2. Preconfigured Redux, GraphQL client and i18n out-of-the-box. *(You can disable Redux/GraphQL client if you're not using it, it'll only leave minimum trace in your build)* 3. Server-side rendering, code-splitting and hot-module replacement configured out-of-the-box. 4. CSS Modules support with CSS, LESS, or SASS syntax with autoprefixer, or use any CSS-in-JS library that you like! diff --git a/packages/treats/alias.js b/packages/treats/alias.js index def050c..da78cbb 100644 --- a/packages/treats/alias.js +++ b/packages/treats/alias.js @@ -2,13 +2,41 @@ const fs = require("fs-extra"), path = require("path"), RESOLVER = require("./resolver"), ROOT_PATH = process.cwd(), - configPath = path.resolve(ROOT_PATH, "./treats.config.js"); + configPath = path.resolve(ROOT_PATH, "./treats.config.js"), + configPathTypescript = path.resolve(ROOT_PATH, "./treats.config.ts"), + isTSFileExists = require("./scripts/util/isTSFileExists"); let userAlias = {}; + +//Capturing all user-defined alias in Treats config if (fs.pathExistsSync(configPath)) { + //Capturing user alias from treats.config.js userAlias = require(configPath).alias; +} else if (fs.pathExistsSync(configPathTypescript)) { + //Use treats.config.ts if present + userAlias = require(configPathTypescript).alias; } +/** + * A method to select path matching with the current configuration + */ +const selectPath = (useTypescript, currentResolver) => { + const { custom, customTypescript, default: def } = currentResolver; + //If tsconfig.json and typescript filesystem hooks found + if (useTypescript && fs.pathExistsSync(customTypescript)) { + return customTypescript; + } + + //If no tsconfig.json nor typescript filesystem hooks found + if (fs.pathExistsSync(custom)) { + return custom; + } + + //If no filsystem hooks found, return default path + return def; +}; + +//Core paths const CORE_PATH = path.resolve(__dirname), CORE_SERVER_PATH = path.resolve(CORE_PATH, "./server"), CORE_CLIENT_PATH = path.resolve(CORE_PATH, "./client"), @@ -19,16 +47,18 @@ const CORE_PATH = path.resolve(__dirname), CORE_FLOW_TYPED_PATH = path.resolve(CORE_PATH, "./flow-typed"), CORE_REDUX_PROXY_PATH = path.resolve(CORE_PATH, "./shared/proxy/redux.js"), CORE_ROUTER_PROXY_PATH = path.resolve(CORE_PATH, "./shared/proxy/router.js"), + useTypescript = isTSFileExists(), + //Filesystem hooks scan resolvedAlias = Object.keys(RESOLVER).reduce((accumulator, key) => { - const { custom, default: def } = RESOLVER[key]; if (process.env.NODE_ENV !== "test") { - accumulator[`@@${key}@@`] = fs.pathExistsSync(custom) ? custom : def; + accumulator[`@@${key}@@`] = selectPath(useTypescript, RESOLVER[key]); } else { - accumulator[`@@${key}@@`] = def; + accumulator[`@@${key}@@`] = RESOLVER[key].default; } return accumulator; }, {}); +//Overwrite userAlias with Core and Resolved Alias const alias = { ...userAlias, "@ROOT_DIR@": ROOT_PATH, diff --git a/packages/treats/generator/component/<%COMPONENT_NAME%>/<%COMPONENT_NAME%>.js b/packages/treats/generator/component/<%COMPONENT_NAME%>/<%COMPONENT_NAME%>.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> similarity index 72% rename from packages/treats/generator/component/<%COMPONENT_NAME%>/<%COMPONENT_NAME%>.js rename to packages/treats/generator/component/<%COMPONENT_NAME%>/<%COMPONENT_NAME%>.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> index 59fa7f7..b2c6c2b 100644 --- a/packages/treats/generator/component/<%COMPONENT_NAME%>/<%COMPONENT_NAME%>.js +++ b/packages/treats/generator/component/<%COMPONENT_NAME%>/<%COMPONENT_NAME%>.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> @@ -2,6 +2,11 @@ import React<%if(COMPONENT_TYPE === "ClassComponent")%>, { Component }<%elsif(CO <%if(CODE_SPLIT)%>import AsyncComponent from "@treats/component/async-component";<%endif%> <%if(COMPONENT_WITH_REDUX)%>import { connect } from "@treats/redux";<%endif%> import style from "./<%COMPONENT_NAME%>.css"; +<%if(USE_TYPESCRIPT)%><%if(COMPONENT_PROPS && COMPONENT_PROPS.length > 0)%> +type PropsType = { + <%for(let i=0; i< COMPONENT_PROPS.length; i++)%><%COMPONENT_PROPS[i]%>: any; + <%endfor%> +};<%endif%><%endif%> /** * <%COMPONENT_DESCRIPTION%><%if(COMPONENT_PROPS && COMPONENT_PROPS.length > 0)%> @@ -9,7 +14,7 @@ import style from "./<%COMPONENT_NAME%>.css"; * @param props.<%COMPONENT_PROPS[i]%><%endfor%><%endif%> * */<%if(COMPONENT_TYPE === "ClassComponent" || COMPONENT_TYPE === "ClassPureComponent")%> -class <%COMPONENT_NAME_VAR%> extends <%if(COMPONENT_TYPE === "ClassComponent")%>Component<%elsif(COMPONENT_TYPE === "ClassPureComponent")%>PureComponent<%endif%> { +class <%COMPONENT_NAME_VAR%> extends <%if(COMPONENT_TYPE === "ClassComponent")%>Component<%elsif(COMPONENT_TYPE === "ClassPureComponent")%>PureComponent<%endif%><%if(USE_TYPESCRIPT)%><%if(COMPONENT_PROPS && COMPONENT_PROPS.length > 0)%><%endif%><%endif%> { render() { <%if(COMPONENT_PROPS && COMPONENT_PROPS.length > 0)%>const { <%COMPONENT_PROPS.join(", ")%> } = this.props<%endif%> return( @@ -18,14 +23,14 @@ class <%COMPONENT_NAME_VAR%> extends <%if(COMPONENT_TYPE === "ClassComponent")%> } } <%else%> -const <%COMPONENT_NAME_VAR%> = (<%if(COMPONENT_PROPS && COMPONENT_PROPS.length > 0)%>{ <%COMPONENT_PROPS.join(", ")%> }<%endif%>) => ( +const <%COMPONENT_NAME_VAR%> = (<%if(COMPONENT_PROPS && COMPONENT_PROPS.length > 0)%>{ <%COMPONENT_PROPS.join(", ")%> }<%endif%><%if(USE_TYPESCRIPT)%><%if(COMPONENT_PROPS && COMPONENT_PROPS.length > 0)%>: PropsType<%endif%><%endif%>) => (
**Your Component Code Goes Here**
); <%endif%><%if(COMPONENT_WITH_REDUX)%> -const mapStateToProps = state => ({ +const mapStateToProps = <%if(USE_TYPESCRIPT)%>(state: any)<%else%>state<%endif%> => ({ /** YOUR MAP STATE TO PROPS FUNCTION */ }); -const mapDispatchToProps = dispatch => ({ +const mapDispatchToProps = <%if(USE_TYPESCRIPT)%>(dispatch: Function)<%else%>dispatch<%endif%> => ({ /** YOUR MAP DISPATCH TO PROPS FUNCTION */ }); <%endif%> diff --git a/packages/treats/generator/component/<%COMPONENT_NAME%>/index.js b/packages/treats/generator/component/<%COMPONENT_NAME%>/index.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> similarity index 100% rename from packages/treats/generator/component/<%COMPONENT_NAME%>/index.js rename to packages/treats/generator/component/<%COMPONENT_NAME%>/index.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> diff --git a/packages/treats/generator/component/treats-generator.json b/packages/treats/generator/component/treats-generator.json index ca4fb3d..d4da977 100644 --- a/packages/treats/generator/component/treats-generator.json +++ b/packages/treats/generator/component/treats-generator.json @@ -51,6 +51,12 @@ "default": false, "required": true }, + "USE_TYPESCRIPT": { + "description": "Do you want to use Typescipt?", + "type": "boolean", + "default": false, + "required": true + }, "COMPONENT_PROPS": { "description": "Component props", "type": "array", diff --git a/packages/treats/generator/helper/<%HELPER_NAME%>/<%HELPER_NAME%>.js b/packages/treats/generator/helper/<%HELPER_NAME%>/<%HELPER_NAME%>.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 91% rename from packages/treats/generator/helper/<%HELPER_NAME%>/<%HELPER_NAME%>.js rename to packages/treats/generator/helper/<%HELPER_NAME%>/<%HELPER_NAME%>.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> index d17884e..1104183 100644 --- a/packages/treats/generator/helper/<%HELPER_NAME%>/<%HELPER_NAME%>.js +++ b/packages/treats/generator/helper/<%HELPER_NAME%>/<%HELPER_NAME%>.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -8,7 +8,7 @@ const <%HELPER_NAME_VAR%>= { * @param app Express App * @param envVars App's Environment Variables */ - init(app, envVars) { + init(app<%if(USE_TYPESCRIPT)%>: any<%endif%>, envVars<%if(USE_TYPESCRIPT)%>: any<%endif%>) { this.app = app; app.set("<%HELPER_NAME%>", this); /** YOUR INITIALIZATION CODE GOES HERE */ diff --git a/packages/treats/generator/helper/<%HELPER_NAME%>/index.js b/packages/treats/generator/helper/<%HELPER_NAME%>/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 100% rename from packages/treats/generator/helper/<%HELPER_NAME%>/index.js rename to packages/treats/generator/helper/<%HELPER_NAME%>/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> diff --git a/packages/treats/generator/helper/treats-generator.json b/packages/treats/generator/helper/treats-generator.json index 7482f4b..0f5c87c 100644 --- a/packages/treats/generator/helper/treats-generator.json +++ b/packages/treats/generator/helper/treats-generator.json @@ -31,6 +31,12 @@ "description": "Helper description", "default": "My Treats Helper", "required": true + }, + "USE_TYPESCRIPT": { + "description": "Do you want to use Typescipt?", + "type": "boolean", + "default": false, + "required": true } }, "beforeGenerate": [ diff --git a/packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/<%MIDDLEWARE_NAME%>.js b/packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/<%MIDDLEWARE_NAME%>.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 84% rename from packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/<%MIDDLEWARE_NAME%>.js rename to packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/<%MIDDLEWARE_NAME%>.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> index b8267fb..90b1d54 100644 --- a/packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/<%MIDDLEWARE_NAME%>.js +++ b/packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/<%MIDDLEWARE_NAME%>.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -7,7 +7,7 @@ const <%MIDDLEWARE_NAME_VAR%> = {<%if(MIDDLEWARE_WITH_INIT)%> * @param app Express App * @param envVars App's Environment Variable */ - init(app, envVars) { + init(app<%if(USE_TYPESCRIPT)%>: any<%endif%>, envVars<%if(USE_TYPESCRIPT)%>: any<%endif%>) { /** YOUR INITIALIZATION CODE GOES HERE */ },<%endif%> /** @@ -16,7 +16,7 @@ const <%MIDDLEWARE_NAME_VAR%> = {<%if(MIDDLEWARE_WITH_INIT)%> * @param res Express Response Object * @param next Express Next Function */ - middleware(req, res, next) { + middleware(req<%if(USE_TYPESCRIPT)%>: any<%endif%>, res<%if(USE_TYPESCRIPT)%>: any<%endif%>, next<%if(USE_TYPESCRIPT)%>: Function<%endif%>) { if (!req.error) { const { app } = req, appConfig = app.get("config"), diff --git a/packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/index.js b/packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 100% rename from packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/index.js rename to packages/treats/generator/middleware/<%MIDDLEWARE_NAME%>/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> diff --git a/packages/treats/generator/middleware/treats-generator.json b/packages/treats/generator/middleware/treats-generator.json index 0fc3723..97aeb57 100644 --- a/packages/treats/generator/middleware/treats-generator.json +++ b/packages/treats/generator/middleware/treats-generator.json @@ -37,6 +37,12 @@ "description": "Middleware description", "default": "My Treats Middleware", "required": true + }, + "USE_TYPESCRIPT": { + "description": "Do you want to use Typescipt?", + "type": "boolean", + "default": false, + "required": true } }, "beforeGenerate": [ diff --git a/packages/treats/generator/redux/<%REDUX_NAME%>/action.js b/packages/treats/generator/redux/<%REDUX_NAME%>/action.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 81% rename from packages/treats/generator/redux/<%REDUX_NAME%>/action.js rename to packages/treats/generator/redux/<%REDUX_NAME%>/action.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> index 69cb44a..912652f 100644 --- a/packages/treats/generator/redux/<%REDUX_NAME%>/action.js +++ b/packages/treats/generator/redux/<%REDUX_NAME%>/action.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -20,7 +20,7 @@ const <%REDUX_THUNKS[i]%>Error = () => ({ * An action creator for setting <%REDUX_THUNKS[i]%> success state. * @private */ -const <%REDUX_THUNKS[i]%>Success = () => ({ +const <%REDUX_THUNKS[i]%>Success = (response<%if(USE_TYPESCRIPT)%>: any<%endif%>) => ({ type: types["<%REDUX_NAME_VAR.toUpperCase()%>/<%REDUX_THUNKS[i].toUpperCase()%>_SUCCESS"] }); @@ -28,14 +28,14 @@ const <%REDUX_THUNKS[i]%>Success = () => ({ * A thunk to dispatch actions for <%REDUX_THUNKS[i]%> * @public */ -const <%REDUX_THUNKS[i]%> = () => (dispatch, getState) => { +const <%REDUX_THUNKS[i]%> = () => (dispatch<%if(USE_TYPESCRIPT)%>: Function<%endif%>, getState<%if(USE_TYPESCRIPT)%>: Function<%endif%>) => { /** Your thunk code for "<%REDUX_THUNKS[i]%>" goes here */ dispatch(<%REDUX_THUNKS[i]%>Loading()); const <%REDUX_THUNKS[i]%>Promise = new Promise() - .then(response => { + .then(<%if(USE_TYPESCRIPT)%>(response: any)<%else%>response<%endif%> => { dispatch(<%REDUX_THUNKS[i]%>Success(response)); }) - .catch(err => { + .catch(<%if(USE_TYPESCRIPT)%>(err: any)<%else%>err<%endif%> => { console.error("[<%REDUX_THUNKS[i]%>] <%REDUX_THUNKS[i]%> Error"); console.error(err); dispatch(<%REDUX_THUNKS[i]%>Error()); diff --git a/packages/treats/generator/redux/<%REDUX_NAME%>/index.js b/packages/treats/generator/redux/<%REDUX_NAME%>/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 100% rename from packages/treats/generator/redux/<%REDUX_NAME%>/index.js rename to packages/treats/generator/redux/<%REDUX_NAME%>/index.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> diff --git a/packages/treats/generator/redux/<%REDUX_NAME%>/initial-state.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> b/packages/treats/generator/redux/<%REDUX_NAME%>/initial-state.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> new file mode 100644 index 0000000..992cbdc --- /dev/null +++ b/packages/treats/generator/redux/<%REDUX_NAME%>/initial-state.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -0,0 +1,9 @@ +const initialState = <%if(!USE_TYPESCRIPT)%>undefined;<%else%>{ + /**YOUR STATE GOES HERE**/ +}; + +export interface StateType { + /**YOUR STATE TYPE DEFINITION GOES HERE**/ +}<%endif%> + +export default initialState; diff --git a/packages/treats/generator/redux/<%REDUX_NAME%>/initial-state.js b/packages/treats/generator/redux/<%REDUX_NAME%>/initial-state.js deleted file mode 100644 index d1da8a7..0000000 --- a/packages/treats/generator/redux/<%REDUX_NAME%>/initial-state.js +++ /dev/null @@ -1,3 +0,0 @@ -const initialState = undefined; - -export default initialState; diff --git a/packages/treats/generator/redux/<%REDUX_NAME%>/reducer.js b/packages/treats/generator/redux/<%REDUX_NAME%>/reducer.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 65% rename from packages/treats/generator/redux/<%REDUX_NAME%>/reducer.js rename to packages/treats/generator/redux/<%REDUX_NAME%>/reducer.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> index 4542ee9..372ed7b 100644 --- a/packages/treats/generator/redux/<%REDUX_NAME%>/reducer.js +++ b/packages/treats/generator/redux/<%REDUX_NAME%>/reducer.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> @@ -1,19 +1,19 @@ -import initialState from "./initial-state"; +import initialState<%if(USE_TYPESCRIPT)%>, { StateType }<%endif%> from "./initial-state"; import types from "./type"; /** * An action handler for handling <%REDUX_NAME%>. */ const <%REDUX_NAME_VAR%>ActionHandlers = {<%if(REDUX_THUNKS && REDUX_THUNKS.length > 0)%><%for(let i=0; i< REDUX_THUNKS.length; i++)%> - [types["<%REDUX_NAME_VAR.toUpperCase()%>/<%REDUX_THUNKS[i].toUpperCase()%>_LOADING"]]: state => { + [types["<%REDUX_NAME_VAR.toUpperCase()%>/<%REDUX_THUNKS[i].toUpperCase()%>_LOADING"]]: <%if(USE_TYPESCRIPT)%>(state: StateType, action: any)<%else%>state<%endif%> => { /** YOUR CODE GOES HERE FOR <%REDUX_THUNKS[i]%> Loading*/ return state; }, - [types["<%REDUX_NAME_VAR.toUpperCase()%>/<%REDUX_THUNKS[i].toUpperCase()%>_ERROR"]]: state => { + [types["<%REDUX_NAME_VAR.toUpperCase()%>/<%REDUX_THUNKS[i].toUpperCase()%>_ERROR"]]: <%if(USE_TYPESCRIPT)%>(state: StateType, action: any)<%else%>state<%endif%> => { /** YOUR CODE GOES HERE FOR <%REDUX_THUNKS[i]%> Error*/ return state; }, - [types["<%REDUX_NAME_VAR.toUpperCase()%>/<%REDUX_THUNKS[i].toUpperCase()%>_SUCCESS"]]: state => { + [types["<%REDUX_NAME_VAR.toUpperCase()%>/<%REDUX_THUNKS[i].toUpperCase()%>_SUCCESS"]]: <%if(USE_TYPESCRIPT)%>(state: StateType, action: any)<%else%>state<%endif%> => { /** YOUR CODE GOES HERE FOR <%REDUX_THUNKS[i]%> Success*/ return state; },<%endfor%><%endif%> @@ -25,7 +25,7 @@ const <%REDUX_NAME_VAR%>ActionHandlers = {<%if(REDUX_THUNKS && REDUX_THUNKS.leng * @param state the Redux state * @param action action being dispatched */ -const <%REDUX_NAME_VAR%>Reducer = (state = initialState, action) => +const <%REDUX_NAME_VAR%>Reducer = (state<%if(USE_TYPESCRIPT)%>: StateType<%endif%> = initialState, action<%if(USE_TYPESCRIPT)%>: any<%endif%>) => <%REDUX_NAME_VAR%>ActionHandlers[action.type] ? <%REDUX_NAME_VAR%>ActionHandlers[action.type](state, action) : state; export default <%REDUX_NAME_VAR%>Reducer; diff --git a/packages/treats/generator/redux/<%REDUX_NAME%>/type.js b/packages/treats/generator/redux/<%REDUX_NAME%>/type.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> similarity index 100% rename from packages/treats/generator/redux/<%REDUX_NAME%>/type.js rename to packages/treats/generator/redux/<%REDUX_NAME%>/type.<%if(USE_TYPESCRIPT)%>ts<%else%>js<%endif%> diff --git a/packages/treats/generator/redux/treats-generator.json b/packages/treats/generator/redux/treats-generator.json index a3832ba..9e9ef59 100644 --- a/packages/treats/generator/redux/treats-generator.json +++ b/packages/treats/generator/redux/treats-generator.json @@ -27,6 +27,12 @@ "message": "Redux variable name must be only letters, or underscores", "required": true }, + "USE_TYPESCRIPT": { + "description": "Do you want to use Typescipt?", + "type": "boolean", + "default": false, + "required": true + }, "REDUX_THUNKS": { "description": "Redux thunks", "type": "array", diff --git a/packages/treats/generator/test/<%TEST_NAME%>.spec.js b/packages/treats/generator/test/<%TEST_NAME%>.spec.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> similarity index 88% rename from packages/treats/generator/test/<%TEST_NAME%>.spec.js rename to packages/treats/generator/test/<%TEST_NAME%>.spec.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> index 7e43688..44610ee 100644 --- a/packages/treats/generator/test/<%TEST_NAME%>.spec.js +++ b/packages/treats/generator/test/<%TEST_NAME%>.spec.<%if(USE_TYPESCRIPT)%>tsx<%else%>js<%endif%> @@ -4,6 +4,5 @@ describe("<%TEST_NAME%>", () => { <%if(TEST_DESCRIPTION && TEST_DESCRIPTION.length > 0)%><%for(let i=0; i< TEST_DESCRIPTION.length; i++)%> it("<%TEST_DESCRIPTION[i]%>", () => { /** YOUR TEST GOES HERE */ - }); - <%endfor%><%endif%> + });<%endfor%><%endif%> }); diff --git a/packages/treats/generator/test/treats-generator.json b/packages/treats/generator/test/treats-generator.json index 10936af..9ec6b6f 100644 --- a/packages/treats/generator/test/treats-generator.json +++ b/packages/treats/generator/test/treats-generator.json @@ -25,6 +25,12 @@ "pattern": "^[a-zA-Z0-9\\s\\-\\_]+$", "message": "Description must be only letters, number, dash, space, or underscore", "required": false + }, + "USE_TYPESCRIPT": { + "description": "Do you want to use Typescipt?", + "type": "boolean", + "default": false, + "required": true } }, "beforeGenerate": [ diff --git a/packages/treats/lib/treats.d.ts b/packages/treats/lib/treats.d.ts new file mode 100644 index 0000000..40b68ee --- /dev/null +++ b/packages/treats/lib/treats.d.ts @@ -0,0 +1,1400 @@ +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// + +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: "development" | "staging" | "production" | "test", + PUBLIC_URL: string + } +} + +declare module "*.bmp" { + const src: string; + export default src; +} + +declare module "*.gif" { + const src: string; + export default src; +} + +declare module "*.jpg" { + const src: string; + export default src; +} + +declare module "*.jpeg" { + const src: string; + export default src; +} + +declare module "*.png" { + const src: string; + export default src; +} + +declare module "*.svg" { + import * as React from "react"; + + export const ReactComponent: React.SFC>; + + const src: string; + export default src; +} + +declare module '*.css' { + const classes: { [key: string]: string }; + export default classes; +} + +declare module '*.scss' { + const classes: { [key: string]: string }; + export default classes; +} + +declare module '*.sass' { + const classes: { [key: string]: string }; + export default classes; +} + +declare module "*.less" { + const classes: { [key: string]: string }; + export default classes; +} + +//Treats Jest Global Function Declaration +declare const shallow: Function; +declare const render: Function; +declare const mount: Function; +declare const mountWithIntl: Function; +declare const shallowWithIntl: Function; +declare const renderWithIntl: Function; +declare const shallowToJson: Function; +declare const renderToJson: Function; +declare const mountToJson: Function; + +//Treats Core Declaration +declare module "@treats/intl" { + import reactIntl = ReactIntl; + export = reactIntl; +} + +declare module "@treats/helmet" { + import reactHelmet from "react-helmet"; + + export default reactHelmet; +} + +declare module "@treats/router" { + export { + BrowserRouter, + HashRouter, + NavLink, + Prompt, + MemoryRouter, + Route, + Router, + StaticRouter, + Switch, + withRouter, + matchPath + } from "react-router-dom"; + export { default as Redirect } from "@treats/component/redirect"; + export { default as Link } from "@treats/component/link"; +} + +declare module "@treats/route" { + type ModuleType = { [key: string]: string } + type RouteType = { + name: string, + path: string, + exact?: boolean, + disabled?: boolean + component: ModuleType + } + + const routes: Array + export default routes +} + +declare module "@treats/client" { + const initClient: Function; + export default initClient; +} + +declare module "@treats/server" { + const initServer: Function; + export default initServer; +} + +declare module "@treats/redux" { + export * from "redux"; + export * from "react-redux"; +} + +//Treats Util Declaration +declare module "@treats/util/cookie" { + export const getCookie: Function; +} + +declare module "@treats/util/graphql" { + export const mergeApolloConfig: Function; + export const combineLinkStates: Function; +} + +declare module "@treats/util/json" { + export const injectParam: Function; + export const bindParams: Function; +} + +declare module "@treats/util/location" { + export const findActiveRoute: Function; + export const isPushEnabled: Function; + export const getURLfromLocation: Function; +} + +declare module "@treats/util/redux" { + export const mergeReduxState: Function; + export const typeGenerator: Function; + export const reducerGenerator: Function; + export const actionCreatorGenerator: Function; +} + +declare module "@treats/util/security" { + export const deserializeJSON: Function; + export const serializeJSON: Function; + export const escapeHtml: Function; + export const escapeHtmlQueryObject: Function; +} + +declare module "@treats/util/string" { + export const camelToKebabCase: Function; +} + +declare module "@treats/util/typecheck" { + export const isArray: Function; + export const isString: Function; + export const isObject: Function; + export const isNumber: Function; + export const isFunction: Function; +} + + +//Treats Component declaration +declare module "@treats/component/async-component" { + const component: Function; + export default component; +} + +declare module "@treats/component/async-loader" { + const component: Function; + export default component; +} + +declare module "@treats/component/error-boundary" { + import * as React from "react"; + + export const withErrorBoundary: Function; + const component: React.ReactNode; + export default component; +} + +declare module "@treats/component/http-status" { + import * as React from "react"; + + const component: React.ReactNode; + export default component; +} + +declare module "@treats/component/link" { + import * as React from "react"; + + const component: React.ReactNode; + export default component; +} + +declare module "@treats/component/provider" { + import * as React from "react"; + + const component: React.ReactNode; + export default component; +} + +declare module "@treats/component/redirect" { + const component: Route; + export default component; +} + +// These modules is an alias from react-intl/locale-data +declare module "@treats/locale-data/af" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/agq" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ak" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/am" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ar" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/as" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/asa" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ast" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/az" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bas" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/be" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bem" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bez" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bm" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/br" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/brx" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/bs" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ca" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ce" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/cgg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/chr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ckb" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/cs" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/cu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/cy" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/da" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/dav" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/de" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/dje" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/dsb" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/dua" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/dv" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/dyo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/dz" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ebu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ee" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/el" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/en" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/eo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/es" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/et" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/eu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ewo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/fa" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ff" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/fi" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/fil" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/fo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/fr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/fur" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/fy" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ga" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/gd" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/gl" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/gsw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/gu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/guw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/guz" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/gv" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ha" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/haw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/he" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/hi" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/hr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/hsb" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/hu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/hy" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/id" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ig" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ii" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/in" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/is" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/it" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/iu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/iw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ja" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/jbo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/jgo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ji" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/jmc" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/jv" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/jw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ka" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kab" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kaj" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kam" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kcg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kde" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kea" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/khq" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ki" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kk" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kkj" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kl" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kln" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/km" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ko" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kok" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ks" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ksb" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ksf" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ksh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ku" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/kw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ky" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lag" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lb" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lkt" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ln" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lrc" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lt" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/luo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/luy" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/lv" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mas" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mer" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mfe" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mgh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mgo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mk" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ml" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ms" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mt" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mua" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/my" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/mzn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nah" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/naq" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nb" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nd" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ne" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nl" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nmg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nnh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/no" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nqo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nso" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nus" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ny" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/nyn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/om" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/or" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/os" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/pa" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/pap" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/pl" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/prg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ps" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/pt" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/qu" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/rm" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/rn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ro" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/rof" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ru" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/rw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/rwk" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sah" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/saq" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sbp" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sdh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/se" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/seh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ses" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sg" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/shi" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/si" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sk" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sl" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sma" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/smi" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/smj" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/smn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sms" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/so" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sq" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ss" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ssy" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/st" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sv" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/sw" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/syr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ta" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/te" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/teo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/th" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ti" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/tig" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/tk" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/tl" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/tn" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/to" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/tr" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ts" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/twq" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/tzm" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ug" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/uk" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ur" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/uz" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/vai" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/ve" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/vi" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/vo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/vun" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/wa" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/wae" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/wo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/xh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/xog" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/yav" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/yi" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/yo" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/zgh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/zh" { + const data: ReactIntl.LocaleData; + export = data; +} + +declare module "@treats/locale-data/zu" { + const data: ReactIntl.LocaleData; + export = data; +} diff --git a/packages/treats/package.json b/packages/treats/package.json index 6c974b2..b773c2c 100644 --- a/packages/treats/package.json +++ b/packages/treats/package.json @@ -4,6 +4,7 @@ "version": "0.1.1", "description": "Tokopedia React Development Kits", "author": "Tokopedia Engineering", + "types": "./lib/treats.d.ts", "main": "./index.js", "bin": { "treats": "./index.js" @@ -59,6 +60,7 @@ "babel-merge": "2.0.1", "babel-plugin-react-intl": "3.0.1", "babel-plugin-universal-import": "3.1.1", + "cache-loader": "2.0.0", "canduit": "1.3.1", "chokidar": "2.0.4", "circular-dependency-plugin": "5.0.2", @@ -73,6 +75,7 @@ "express": "4.16.3", "extract-css-chunks-webpack-plugin": "3.2.1", "file-loader": "2.0.0", + "fork-ts-checker-webpack-plugin": "0.5.2", "fs-extra": "5.0.0", "glob": "7.1.2", "graphql": "0.13.2", @@ -117,6 +120,7 @@ "semver": "5.5.0", "serialize-javascript": "1.5.0", "thread-loader": "1.2.0", + "ts-loader": "5.3.2", "unfetch": "3.0.0", "webpack": "4.23.1", "webpack-bundle-analyzer": "3.0.3", diff --git a/packages/treats/resolver.js b/packages/treats/resolver.js index 98eae32..cef592d 100644 --- a/packages/treats/resolver.js +++ b/packages/treats/resolver.js @@ -1,61 +1,79 @@ const path = require("path"), ROOT_PATH = process.cwd(); +/** + * Treats filesystem hooks with 3 config [custom, customTypescript, default]. + * custom or customTypescript will be used when you define them on your projects + */ const RESOLVER = { BUILD_SERVER_APP_PATH: { custom: path.resolve(ROOT_PATH, "./src/_server"), + customTypescript: path.resolve(ROOT_PATH, "./src/_server"), default: path.resolve(__dirname, "./default/_server") }, BUILD_CLIENT_APP_PATH: { custom: path.resolve(ROOT_PATH, "./src/_client"), + customTypescript: path.resolve(ROOT_PATH, "./src/_client"), default: path.resolve(__dirname, "./default/_client") }, BUILD_ROUTE_PATH: { custom: path.resolve(ROOT_PATH, "./src/_route/route.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_route/route.ts"), default: path.resolve(__dirname, "./default/_route/route.js") }, BUILD_ROUTE_MODULE_PATH: { custom: path.resolve(ROOT_PATH, "./src/_route/module.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_route/module.ts"), default: path.resolve(__dirname, "./default/_route/module.js") }, BUILD_SERVER_TEMPLATE_PATH: { custom: path.resolve(ROOT_PATH, "./src/_server/template.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_server/template.ts"), default: path.resolve(__dirname, "./default/_server/template.js") }, BUILD_REDUX_MIDDLEWARE_PATH: { custom: path.resolve(ROOT_PATH, "./src/_redux/middleware.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_redux/middleware.ts"), default: path.resolve(__dirname, "./default/_redux/middleware.js") }, BUILD_REDUX_REDUCER_PATH: { custom: path.resolve(ROOT_PATH, "./src/_redux/reducer.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_redux/reducer.ts"), default: path.resolve(__dirname, "./default/_redux/reducer.js") }, BUILD_GRAPHQL_LINK_STATE_PATH: { custom: path.resolve(ROOT_PATH, "./src/_graphql/link-state.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_graphql/link-state.ts"), default: path.resolve(__dirname, "./default/_graphql/link-state.js") }, BUILD_GRAPHQL_URI_PATH: { custom: path.resolve(ROOT_PATH, "./src/_graphql/uri.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_graphql/uri.ts"), default: path.resolve(__dirname, "./default/_graphql/uri.js") }, BUILD_GRAPHQL_CLIENT_CONFIG_PATH: { custom: path.resolve(ROOT_PATH, "./src/_graphql/config.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_graphql/config.ts"), default: path.resolve(__dirname, "./default/_graphql/config.js") }, BUILD_REACT_APP_PATH: { custom: path.resolve(ROOT_PATH, "./src/_app/index.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_app/index.ts"), default: path.resolve(__dirname, "./default/_app/index.js") }, BUILD_GLOBAL_CSS_PATH: { custom: path.resolve(ROOT_PATH, "./src/_app/app.css"), + customTypescript: path.resolve(ROOT_PATH, "./src/_app/app.css"), default: path.resolve(__dirname, "./default/_app/app.css") }, BUILD_LOCALE_PATH: { custom: path.resolve(ROOT_PATH, "./src/_locale"), + customTypescript: path.resolve(ROOT_PATH, "./src/_locale"), default: path.resolve(__dirname, "./default/_locale") }, BUILD_LOCALE_DATA_RESOLVER_PATH: { custom: path.resolve(ROOT_PATH, "./src/_locale/resolver.js"), + customTypescript: path.resolve(ROOT_PATH, "./src/_locale/resolver.ts"), default: path.resolve(__dirname, "./default/_locale/resolver.js") } }; diff --git a/packages/treats/scripts/build b/packages/treats/scripts/build index 038a797..a592285 100644 --- a/packages/treats/scripts/build +++ b/packages/treats/scripts/build @@ -2,7 +2,10 @@ //# vi: ft=javascript const logger = require("./util/logger"), webpack = require("webpack"), - clean = require("./clean"); + clean = require("./clean"), + fs = require("fs-extra"), + path = require("path"), + ROOT_PATH = process.cwd(); const build = argv => { try { @@ -53,8 +56,24 @@ const build = argv => { clean(argv, () => { const loadTreatsConfig = require("./util/load-config"), + checkTypescript = require("./util/checkTypescript"), + generateTSConfig = require("./util/generateTSConfig"), + isTSFileExists = require("./util/isTSFileExists"), { webpack: webpackConfig } = loadTreatsConfig(), - configs = [webpackConfig.server, webpackConfig.client]; + configs = [webpackConfig.server, webpackConfig.client], + useTypescript = isTSFileExists(), + userConfigPath = path.resolve(ROOT_PATH, "./treats.config.js"), + userConfigPathTypescript = path.resolve(ROOT_PATH, "./treats.config.ts");; + + // Check typescript dependencies + checkTypescript(useTypescript); + + // Generate tsconfig.json if ts/tsx files found in projects + if (useTypescript && fs.existsSync(userConfigPath)) { + generateTSConfig(userConfigPath); + } else if (useTypescript && fs.existsSync(userConfigPathTypescript)) { + generateTSConfig(userConfigPathTypescript); + } if(process.env.WEBPACK_OP === "analyze") { logger("log", `Analyze build target ${argv.target} for ${process.env.NODE_ENV} environment`); @@ -70,7 +89,7 @@ const build = argv => { webpackBuild(webpackConfig.client); break; default: - if(!argv.target) { + if(argv.target) { webpackBuild(configs); } else { logger("warn", "Target unknown, can't build!"); diff --git a/packages/treats/scripts/config/jest.config.js b/packages/treats/scripts/config/jest.config.js index 93df241..c8e2cae 100644 --- a/packages/treats/scripts/config/jest.config.js +++ b/packages/treats/scripts/config/jest.config.js @@ -21,7 +21,7 @@ let finalJestConfig = { ], testURL: "http://localhost/", transform: { - "^.+\\.(js|jsx)?$": path.resolve(__dirname, "./jestTransformer.js") + "^.+\\.(js|jsx|ts|tsx)?$": path.resolve(__dirname, "./jestTransformer.js") }, transformIgnorePatterns: ["node_modules/(?!(treats)/)"], snapshotSerializers: ["enzyme-to-json/serializer"], diff --git a/packages/treats/scripts/config/webpack.config.client.build.js b/packages/treats/scripts/config/webpack.config.client.build.js index 1ac67b6..8d86ae8 100644 --- a/packages/treats/scripts/config/webpack.config.client.build.js +++ b/packages/treats/scripts/config/webpack.config.client.build.js @@ -7,7 +7,8 @@ const webpack = require("webpack"), babelOptions = require("./babel.config"), webpackMerge = require("webpack-merge"), babelMerge = require("babel-merge"), - extractEnv = require("./util/extract-env"); + extractEnv = require("./util/extract-env"), + useTypescript = fs.pathExistsSync(path.resolve(process.cwd(), "./tsconfig.json")); module.exports = ({ alias, @@ -24,7 +25,7 @@ module.exports = ({ publicPath = webpackConfig.publicPath || "/static/", clientOutputPath = webpackConfig.clientOutputPath || "public", resolve = { - extensions: [".js", ".css"] + extensions: [".ts", ".tsx", ".js", ".css"] }; const bundleAnalyzerPlugin = webpackOp === "analyze" ? [new BundleAnalyzerPlugin()] : []; @@ -59,7 +60,7 @@ module.exports = ({ module: { rules: [ { - test: /\.js?$/, + test: /\.(js|jsx)?$/, use: [ "thread-loader", { @@ -69,6 +70,25 @@ module.exports = ({ ], exclude: /node_modules\/(?!(treats|@treats)\/).*/ }, + { + test: /\.(ts|tsx)?$/, + use: [ + "cache-loader", + "thread-loader", + { + loader: "ts-loader", + options: { + // IMPORTANT! use happyPackMode mode to speed-up compilation and reduce errors reported to webpack + happyPackMode: true + } + }, + { + loader: "babel-loader", + options: babelMerge(babelConfig, babelOptions) + } + ], + exclude: /node_modules\/(?!(treats|@treats)\/).*/ + }, { test: /\.(graphql|gql)$/, exclude: /node_modules\/(?!(treats|@treats)\/).*/, @@ -254,6 +274,10 @@ module.exports = ({ } }; let finalConfig = defaultConfig; + if (useTypescript) { + const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); + finalConfig.plugins.push(new ForkTsCheckerWebpackPlugin({ checkSyntacticError: true })); + } if (webpackConfig.client) { finalConfig = webpackMerge.smart(defaultConfig, webpackConfig.client); } diff --git a/packages/treats/scripts/config/webpack.config.client.development.js b/packages/treats/scripts/config/webpack.config.client.development.js index e91a391..5c58f7c 100644 --- a/packages/treats/scripts/config/webpack.config.client.development.js +++ b/packages/treats/scripts/config/webpack.config.client.development.js @@ -6,7 +6,8 @@ const webpack = require("webpack"), babelOptions = require("./babel.config"), webpackMerge = require("webpack-merge"), babelMerge = require("babel-merge"), - extractEnv = require("./util/extract-env"); + extractEnv = require("./util/extract-env"), + useTypescript = fs.pathExistsSync(path.resolve(process.cwd(), "./tsconfig.json")); module.exports = ({ alias, @@ -23,7 +24,7 @@ module.exports = ({ publicPath = webpackConfig.publicPath || "/__TREATS_WDS__/", assetsOutputPath = webpackConfig.assetsOutputPath || "public", resolve = { - extensions: [".js", ".css", ".json", ".wasm", ".mjs"] + extensions: [".ts", ".tsx", ".js", ".css", ".json", ".wasm", ".mjs"] }; const defaultConfig = { @@ -62,7 +63,7 @@ module.exports = ({ module: { rules: [ { - test: /\.js?$/, + test: /\.(js|jsx)?$/, use: [ { loader: "thread-loader", @@ -77,6 +78,30 @@ module.exports = ({ ], exclude: /node_modules\/(?!(treats|@treats)\/).*/ }, + { + test: /\.(ts|tsx)?$/, + use: [ + "cache-loader", + { + loader: "thread-loader", + options: { + poolTimeout: Infinity // keep workers alive for more effective watch mode + } + }, + { + loader: "ts-loader", + options: { + // IMPORTANT! use happyPackMode mode to speed-up compilation and reduce errors reported to webpack + happyPackMode: true + } + }, + { + loader: "babel-loader", + options: babelMerge(babelConfig, babelOptions) + } + ], + exclude: /node_modules\/(?!(treats|@treats)\/).*/ + }, { test: /\.(graphql|gql)$/, exclude: /node_modules\/(?!(treats|@treats)\/).*/, @@ -271,11 +296,15 @@ module.exports = ({ output: { path: path.join(__dirname, assetsOutputPath), publicPath, - chunkFilename: "[name].js", + chunkFilename: "[name].chunk.js", filename: "[name].js" } }; let finalConfig = defaultConfig; + if (useTypescript) { + const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); + finalConfig.plugins.push(new ForkTsCheckerWebpackPlugin({ checkSyntacticError: true })); + } if (webpackConfig.client) { finalConfig = webpackMerge.smart(defaultConfig, webpackConfig.client); } diff --git a/packages/treats/scripts/config/webpack.config.server.build.js b/packages/treats/scripts/config/webpack.config.server.build.js index a0149e7..20fd1d1 100644 --- a/packages/treats/scripts/config/webpack.config.server.build.js +++ b/packages/treats/scripts/config/webpack.config.server.build.js @@ -8,7 +8,8 @@ const webpack = require("webpack"), babelOptions = require("./babel.config"), babelMerge = require("babel-merge"), webpackMerge = require("webpack-merge"), - extractEnv = require("./util/extract-env"); + extractEnv = require("./util/extract-env"), + useTypescript = fs.pathExistsSync(path.resolve(process.cwd(), "./tsconfig.json")); module.exports = ({ alias, @@ -25,7 +26,7 @@ module.exports = ({ publicPath = webpackConfig.publicPath || "/static/", serverOutputPath = webpack.serverOutputPath || "dist", resolve = { - extensions: [".js", ".css"] + extensions: [".ts", ".tsx", ".js", ".css"] }; const bundleAnalyzerPlugin = webpackOp === "analyze" ? [new BundleAnalyzerPlugin()] : []; @@ -52,7 +53,7 @@ module.exports = ({ module: { rules: [ { - test: /\.js?$/, + test: /\.(js|jsx)?$/, use: [ "thread-loader", { @@ -62,6 +63,25 @@ module.exports = ({ ], exclude: /node_modules\/(?!(treats|@treats)\/).*/ }, + { + test: /\.(ts|tsx)?$/, + use: [ + "cache-loader", + "thread-loader", + { + loader: "ts-loader", + options: { + // IMPORTANT! use happyPackMode mode to speed-up compilation and reduce errors reported to webpack + happyPackMode: true + } + }, + { + loader: "babel-loader", + options: babelMerge(babelConfig, babelOptions) + } + ], + exclude: /node_modules\/(?!(treats|@treats)\/).*/ + }, { test: /\.(graphql|gql)$/, exclude: /node_modules\/(?!(treats|@treats)\/).*/, @@ -217,6 +237,10 @@ module.exports = ({ } }; let finalConfig = defaultConfig; + if (useTypescript) { + const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); + finalConfig.plugins.push(new ForkTsCheckerWebpackPlugin({ checkSyntacticError: true })); + } if (webpackConfig.server) { finalConfig = webpackMerge.smart(defaultConfig, webpackConfig.server); } diff --git a/packages/treats/scripts/config/webpack.config.server.development.js b/packages/treats/scripts/config/webpack.config.server.development.js index b00e108..6a923e8 100644 --- a/packages/treats/scripts/config/webpack.config.server.development.js +++ b/packages/treats/scripts/config/webpack.config.server.development.js @@ -7,7 +7,8 @@ const webpack = require("webpack"), babelOptions = require("./babel.config"), babelMerge = require("babel-merge"), webpackMerge = require("webpack-merge"), - extractEnv = require("./util/extract-env"); + extractEnv = require("./util/extract-env"), + useTypescript = fs.pathExistsSync(path.resolve(process.cwd(), "./tsconfig.json")); module.exports = ({ alias, @@ -23,7 +24,7 @@ module.exports = ({ publicPath = webpackConfig.publicPath || "/__TREATS_WDS__/", serverOutputPath = webpack.serverOutputPath || "dist", resolve = { - extensions: [".js", ".css", ".json", ".wasm", ".mjs"] + extensions: [".ts", ".tsx", ".js", ".css", ".json", ".wasm", ".mjs"] }; const defaultConfig = { @@ -50,7 +51,7 @@ module.exports = ({ module: { rules: [ { - test: /\.js?$/, + test: /\.(js|jsx)?$/, use: [ { loader: "thread-loader", @@ -65,6 +66,30 @@ module.exports = ({ ], exclude: /node_modules\/(?!(treats|@treats)\/).*/ }, + { + test: /\.(ts|tsx)?$/, + use: [ + "cache-loader", + { + loader: "thread-loader", + options: { + poolTimeout: Infinity // keep workers alive for more effective watch mode + } + }, + { + loader: "ts-loader", + options: { + // IMPORTANT! use happyPackMode mode to speed-up compilation and reduce errors reported to webpack + happyPackMode: true + } + }, + { + loader: "babel-loader", + options: babelMerge(babelConfig, babelOptions) + } + ], + exclude: /node_modules\/(?!(treats|@treats)\/).*/ + }, { test: /\.(graphql|gql)$/, exclude: /node_modules\/(?!(treats|@treats)\/).*/, @@ -215,6 +240,10 @@ module.exports = ({ } }; let finalConfig = defaultConfig; + if (useTypescript) { + const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); + finalConfig.plugins.push(new ForkTsCheckerWebpackPlugin({ checkSyntacticError: true })); + } if (webpackConfig.server) { finalConfig = webpackMerge.smart(defaultConfig, webpackConfig.server); } diff --git a/packages/treats/scripts/generate b/packages/treats/scripts/generate index 3405366..f998999 100644 --- a/packages/treats/scripts/generate +++ b/packages/treats/scripts/generate @@ -37,6 +37,12 @@ const processFile = (filename, resultFileName, envVars) => { fs.copySync(filename, resultFileName); logger("debug", `Copied file ${resultFileName}`); } else { + const filenameComponents = filename.split("/"), + relativeFilename = filenameComponents[filenameComponents.length - 1]; + if (relativeFilename && templateParser(relativeFilename, envVars) === "") { + logger("debug", `Template ${filename} not generated`); + return true; + } logger("debug", `Found template text file ${filename}`); const templateDataDefault = fs.readFileSync(filename), finalDataDefault = templateParser(templateDataDefault.toString(), envVars); diff --git a/packages/treats/scripts/start b/packages/treats/scripts/start index 067258f..eff0573 100755 --- a/packages/treats/scripts/start +++ b/packages/treats/scripts/start @@ -6,9 +6,13 @@ const chalk = require("chalk"), webpack = require("webpack"), WebpackDevServer = require("webpack-dev-server"), chokidar = require("chokidar"), + fs = require("fs-extra"), ROOT_PATH = process.cwd(), logger = require("./util/logger"), reRequire = require("./util/re-require"), + checkTypescript = require("./util/checkTypescript"), + generateTSConfig = require("./util/generateTSConfig"), + isTSFileExists = require("./util/isTSFileExists"), clean = require("./clean"), RESOLVER = require("../resolver"), WebpackDevServerUtils = require("react-dev-utils/WebpackDevServerUtils"), @@ -19,18 +23,33 @@ let loadTreatsConfig, treatsDevServer, isReload = false; -const startDevServers = argv => { +/** + * A function to load config and start webpack development servers. + * @param argv start command arguments + * @param useTypescript is .(ts|tsx) files found + */ +const startDevServers = (argv, useTypescript) => { if(!assetsDevServer && !treatsDevServer) { clean(argv, () => { loadTreatsConfig = reRequire(path.resolve(__dirname, "./util/load-config")); const treatsConfig = loadTreatsConfig(), { webpack: webpackConfig } = treatsConfig, - [serverCompiler, clientCompiler] = webpack([webpackConfig.server, webpackConfig.client]).compilers; + [serverCompiler, clientCompiler] = webpack([webpackConfig.server, webpackConfig.client]).compilers, + configPath = path.resolve(ROOT_PATH, "./treats.config.js"), + configPathTypescript = path.resolve(ROOT_PATH, "./treats.config.ts"); logger("debug", "Initiating build with the following config..."); if(process.env.TREATS_SCRIPT_DEBUG) { //eslint-disable-next-line console.log(treatsConfig); } + + // Generate tsconfig.json if ts/tsx files found in projects + if (useTypescript && fs.existsSync(configPath)) { + generateTSConfig(configPath); + } else if (useTypescript && fs.existsSync(configPathTypescript)) { + generateTSConfig(configPathTypescript); + } + logger("log", `Starting Treats Dev Server on ${process.env.TREATS_HOST}:${process.env.TREATS_PORT}`); treatsDevServer = serverCompiler.watch(webpackConfig.server.watchOptions, (err, stats) => { if (err) { @@ -73,6 +92,11 @@ const startDevServers = argv => { } } +/** + * A function to stop current running development servers. + * @param argv start command arguments + * @param cb callback function on stop + */ const stopDevServers = (argv, cb) => { if(treatsDevServer) { treatsDevServer.close(() => { @@ -93,19 +117,32 @@ const stopDevServers = (argv, cb) => { } } -const reloadDevServers = argv => { +/** + * A function to reload, happened when detect changes on config files. + * @param argv start command arguments + * @param useTypescript is .(ts|tsx) files exists + */ +const reloadDevServers = (argv, useTypescript) => { if(!isReload) { isReload = true; stopDevServers(argv, () => { - startDevServers(argv); + startDevServers(argv, useTypescript); isReload = false; }); } } +/** + * Treats start main command. Starting development server. + * @param argv start command arguments + */ const start = argv => { const userPort = argv.port || 3000; - + + //Verify typescript process before starting projects. + const useTypescript = isTSFileExists(); + checkTypescript(useTypescript); + getProcessForPort(userPort); WebpackDevServerUtils.choosePort("localhost", userPort).then(resolvedPort => { if(resolvedPort !== null) { @@ -119,11 +156,13 @@ const start = argv => { } const entryFiles = Object.keys(RESOLVER).reduce((accumulator, key) => { - accumulator.push(RESOLVER[key].custom); + const buildPath = useTypescript ? RESOLVER[key].customTypescript : RESOLVER[key].custom; + accumulator.push(buildPath); return accumulator; }, []), configFiles = [ path.resolve(ROOT_PATH, "./treats.config.js"), + path.resolve(ROOT_PATH, "./treats.config.ts"), path.resolve(ROOT_PATH, "./.babelrc") ]; @@ -140,35 +179,35 @@ const start = argv => { logger("clear"); } logger("log", `${chalk.green(changedPath)} Changed, reloading....`); - reloadDevServers(argv); + reloadDevServers(argv, useTypescript); } }).on("add", changedPath => { if(!isReload) { logger("clear"); } logger("log", `${chalk.green(changedPath)} added, reloading....`); - reloadDevServers(argv); + reloadDevServers(argv, useTypescript); }).on("unlink", changedPath => { if(!isReload) { logger("clear"); } logger("log", `${chalk.green(changedPath)} removed, reloading....`); - reloadDevServers(argv); + reloadDevServers(argv, useTypescript); }).on("addDir", changedPath => { if(!isReload) { logger("clear"); } logger("log", `${chalk.green(changedPath)} added, reloading....`); - reloadDevServers(argv); + reloadDevServers(argv, useTypescript); }).on("unlinkDir", changedPath => { if(!isReload) { logger("clear"); } logger("log", `${chalk.green(changedPath)} removed, reloading....`); - reloadDevServers(argv); + reloadDevServers(argv, useTypescript); }); - startDevServers(argv); + startDevServers(argv, useTypescript); } catch (err) { logger("error", err); } diff --git a/packages/treats/scripts/util/checkTypescript.js b/packages/treats/scripts/util/checkTypescript.js new file mode 100644 index 0000000..c6f05fe --- /dev/null +++ b/packages/treats/scripts/util/checkTypescript.js @@ -0,0 +1,59 @@ +const fs = require("fs-extra"), + path = require("path"), + logger = require("./logger"), + chalk = require("chalk"), + ROOT_PATH = process.cwd(); + +/** + * A function to check if developer already installed Treats required Typescript dependencies or not yet. + * @author Martino Christanto Khuangga + */ +const checkTypescript = useTypescript => { + if (useTypescript) { + const nodeModulesPath = path.resolve(ROOT_PATH, "./node_modules"), + dependencies = [ + path.resolve(nodeModulesPath, "./cache-loader"), + path.resolve(nodeModulesPath, "./fork-ts-checker-webpack-plugin"), + path.resolve(nodeModulesPath, "./typescript"), + path.resolve(nodeModulesPath, "./ts-loader"), + path.resolve(nodeModulesPath, "./@types/jest"), + path.resolve(nodeModulesPath, "./@types/node"), + path.resolve(nodeModulesPath, "./@types/react"), + path.resolve(nodeModulesPath, "./@types/react-dom"), + path.resolve(nodeModulesPath, "./@types/react-helmet"), + path.resolve(nodeModulesPath, "./@types/react-intl"), + path.resolve(nodeModulesPath, "./@types/react-redux"), + path.resolve(nodeModulesPath, "./@types/react-router-dom"), + path.resolve(nodeModulesPath, "./@types/redux") + ], + isYarn = fs.pathExistsSync(path.resolve(ROOT_PATH, "./yarn.lock")); + + let isDependenciesValid = true; + dependencies.forEach(dep => { + if (!fs.pathExistsSync(dep)) { + const moduleName = path.relative(nodeModulesPath, dep); + logger( + "error", + `Oops! You don't have ${chalk.bold(moduleName)} in your dependencies.` + ); + logger("error", `Please install ${chalk.bold(moduleName)}`); + logger( + "error", + `Type ${ + isYarn + ? chalk.green(`yarn add ${moduleName}`) + : chalk.green(`npm install ${moduleName}`) + }\n` + ); + isDependenciesValid = false; + } + }); + + if (!isDependenciesValid) { + logger("error", "Aborting process..."); + process.exit(1); + } + } +}; + +module.exports = checkTypescript; diff --git a/packages/treats/scripts/util/generateTSConfig.js b/packages/treats/scripts/util/generateTSConfig.js new file mode 100644 index 0000000..7e37e98 --- /dev/null +++ b/packages/treats/scripts/util/generateTSConfig.js @@ -0,0 +1,78 @@ +const ROOT_PATH = process.cwd(), + fs = require("fs-extra"), + path = require("path"), + logger = require("./logger"), + merge = require("lodash.merge"), + defaultTSConfig = { + compilerOptions: { + target: "es5", + allowJs: true, + skipLibCheck: true, + allowSyntheticDefaultImports: true, + strict: true, + forceConsistentCasingInFileNames: true, + module: "esnext", + moduleResolution: "node", + resolveJsonModule: true, + isolatedModules: true, + jsx: "preserve", + outDir: "./dist/", + esModuleInterop: true, + lib: ["esnext", "dom"], + baseUrl: ".", + paths: { + "@treats/server": ["./node_modules/treats/server"], + "@treats/client": ["./node_modules/treats/client"], + "@treats/component": ["./node_modules/treats/shared/component"], + "@treats/util": ["./node_modules/treats/shared/util"], + "@treats/route": ["./node_modules/treats/shared/route"], + "@treats/alias": ["./node_modules/treats/shared/alias"], + "@treats/redux": ["./node_modules/treats/shared/proxy/redux.js"], + "@treats/router": ["./node_modules/treats/shared/proxy/router.js"], + "@treats/intl": ["./node_modules/react-intl"], + "@treats/helmet": ["./node_modules/react-helmet"], + "@treats/graphql": ["./node_modules/react-apollo"], + "@treats/locale-data": ["./node_modules/react-intl/locale-data"] + } + }, + include: ["src"], + exclude: ["node_modules"] + }; + +/** + * A function to copy user typescript configurations in treats.config.(js|ts) to tsconfig.json + * @param configPath path to treats.config.(js|ts) + */ +const generateTSConfig = configPath => { + const treatsConfig = require(configPath), + userTSConfig = treatsConfig.typescript, + tsConfigJsonPath = path.resolve(ROOT_PATH, "./tsconfig.json"); + let tsConfigJSON = {}; + + const userAlias = Object.keys(treatsConfig.alias).reduce((result, key) => { + result[`${key}/*`] = [`./${path.relative(ROOT_PATH, treatsConfig.alias[key])}/*`]; + return result; + }, {}); + + tsConfigJSON = merge(defaultTSConfig, userTSConfig); + + //Override path from user alias in Treats config + tsConfigJSON.compilerOptions.paths = { + ...tsConfigJSON.compilerOptions.paths, + ...userAlias + }; + + //Writing alias to tsconfig.json + logger("log", "Writing your typescript config into tsconfig.json..."); + fs.writeFileSync( + tsConfigJsonPath, + JSON.stringify(tsConfigJSON, (key, value) => value, 4), + err => { + logger("error", "Error when writing your tsconfig.json"); + logger("error", err.stack || err); + } + ); + logger("log", "tsconfig.json successfully generated!"); +}; + +module.exports = generateTSConfig; diff --git a/packages/treats/scripts/util/isTSFileExists.js b/packages/treats/scripts/util/isTSFileExists.js new file mode 100644 index 0000000..903e56a --- /dev/null +++ b/packages/treats/scripts/util/isTSFileExists.js @@ -0,0 +1,19 @@ +const glob = require("glob"), + path = require("path"), + ROOT_PATH = process.cwd(); + +/** + * A function to check if there's .ts or .tsx files in Treats projects. + * @author Martino Christanto Khuangga + */ +const isTSFileExists = () => { + const tsFiles = glob.sync("**/*.*(ts|tsx)", { cwd: path.resolve(ROOT_PATH, "./src") }); + + if (tsFiles.length > 0) { + return true; + } + + return false; +}; + +module.exports = isTSFileExists; diff --git a/packages/treats/scripts/util/load-config.js b/packages/treats/scripts/util/load-config.js index 74acc18..f7e5e0b 100644 --- a/packages/treats/scripts/util/load-config.js +++ b/packages/treats/scripts/util/load-config.js @@ -3,23 +3,35 @@ const reRequire = require("./re-require"), fs = require("fs-extra"), path = require("path"); +/** + * A function to read user-defined config and bundle it into single config + * @param options options provided by developer when call this method + */ const loadTreatsConfig = options => { const defaultAlias = reRequire("../../alias"), env = process.env.NODE_ENV || "development", configPath = path.resolve(ROOT_PATH, "./treats.config.js"), + configPathTypescript = path.resolve(ROOT_PATH, "./treats.config.ts"), serverWebpackConfigGenerator = require(`../config/webpack.config.server.${ env === "development" ? "development" : "build" }`), clientWebpackConfigGenerator = require(`../config/webpack.config.client.${ env === "development" ? "development" : "build" }`); + let customConfig = {}, webpack, alias = defaultAlias; + + //Initialize customConfig with user-defined treats config if (fs.pathExistsSync(configPath)) { customConfig = reRequire(configPath); + } else if (fs.pathExistsSync(configPathTypescript)) { + //Initialize customConfig with treats.config.ts if exists + customConfig = reRequire(configPathTypescript); } + //Add alias if defined in options if (!options || options.alias !== false) { alias = { ...customConfig.alias, @@ -27,6 +39,7 @@ const loadTreatsConfig = options => { }; } + //Init webpack for client and server if (!options || options.webpack !== false) { webpack = { client: clientWebpackConfigGenerator({ ...customConfig, alias }),