{"data":{"site":{"siteMetadata":{"title":"Serge van den Oever's weblog","author":"Serge van den Oever"}},"markdownRemark":{"id":"386ce40a-920a-53a4-8acf-081ba6c4e369","html":"
In this blog post I describe my adventures to convert an “out of the box” Sitecore 9.1 with JSS in React with TypeScript project from scratch. To get started head over to the Quickstart |Sitecore JSS Documentation\nand follow the steps to create a disconnected JSS starter project:
\nnpm install -g @sitecore-jss/sitecore-jss-cli
jss create hello-jss-typescript react
git init
cd hello-jss-typescript
git init
git add -A
git commit -m "first commit"
git remote add origin https://github.com/macaw-interactive/hello-jss-sitecore.git
git push -u origin master
jss start
We now have the starter website running on http://localhost:3000.
\nNow we can scaffold a new Hero component using jss scaffold Hero
.\nThe scaffolder generates the new component in it’s own folder src/components/Hero
named index.js
.\nThe easy way to introduce TypeScript is described by my colleague Gary Wenneker in his blog post Sitecore JSS: Get Typed!:
Hero.js
to Hero.tsx
npm install typescript @types/node @types/react @types/react-dom
tsconfig.json
tsc --watch
to compile the .ts
and .tsx
files to .js
next to the source fileThe JSS tooling picks up the .js
component files in the script "start:watch-components": "node scripts/generate-component-factory.js --watch"
for mapping the React components to JSS components.
Problem with this approach is that source tree is cluttered with generated .js
files\nnext to the TypeScript files that are difficult to exclude from source control.
In this blog post we describe another approach in using TypeScript in you Sitecore JSS project.\nThe blog post is accompanied by the GitHub repository\nhello-jss-typescript\nwith the required modifications for a simple “Hello world” app as a reference for you\nadventures.
\nThe first step to execute is to install the required TypeScript tooling\nand type definitions:
\nnpm install typescript @types/node @types/react @types/react-dom
Now add a tsconfig.json
file in the root tailered for JSS development.\nBecause the JSS tool-set is based on the magnificent tool-set of Create React App we took as a starter point the\ntsconfig.json
as generated by create-react-app
. We need to make some modifications to tailer it to the needs of the JSS project. Those changes are already\nincluded is the tsconfig.json
below. The rationale behind these changes are described below where appropriate.
{\n \"compilerOptions\": {\n \"target\": \"es5\",\n \"allowJs\": false,\n \"skipLibCheck\": false,\n \"esModuleInterop\": true,\n \"allowSyntheticDefaultImports\": true,\n \"strict\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"node\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"noEmit\": true,\n \"jsx\": \"preserve\",\n \"lib\": [\"es2018\", \"dom\"],\n },\n \"include\": [\n \"src\"\n ],\n \"types\": [\"node\"]\n }
We now scaffold the Hero
component using the command jss scaffold Hero
as\ndescribed in Scaffolding a JSS Component.\nThis will generate two files:
src\\components\\Hero\\index.js
sitecore\\definitions\\components\\Hero.sitecore.js
The generated src\\components\\Hero\\index.js
looks like:
import React from 'react';\nimport { Text } from '@sitecore-jss/sitecore-jss-react';\n\nconst Hero = (props) => (\n <div>\n <p>Hero Component</p>\n <Text field={props.fields.heading} />\n </div>\n);\n\nexport default Hero;
rename the file to src\\components\\Hero\\index.tsx
and rewrite the code to:
import * as React from 'react';\nimport { Text } from '@sitecore-jss/sitecore-jss-react';\n\ntype HeroPropsFields = {\n heading: {\n value?: string;\n editable?: string;\n } \n}\ntype HeroProps = {\n fields: HeroPropsFields;\n};\n\ntype HeroAllProps = HeroProps;\n\nconst Hero: React.SFC<HeroAllProps> = (props: HeroAllProps) => (\n <div>\n <p>Hero Component</p>\n <Text field={props.fields.heading} />\n </div>\n);\n\nexport default Hero;
To include the Hero component in a route layout in disconnected mode open the file data\\routes\\en.yml
\nand add the Hero component to the jss-main
placeholder:
placeholders:\n jss-main:\n - componentName: Hero\n fields:\n heading: Serge's hero component!\n - componentName: ContentBlock\n fields:
The component factory does the mapping op React components to JSS components. It provides\nthe mapping between a string name based on the component folder and name the React component instance.\nWhen the Sitecore Layout service returns a layout definition, it returns the components by name.\nBased on the mapping provided by the component factory the component hierarchy can be\nconstructed for the layout.
\nThe script scripts/generate-component-factory.js
is responsible for the generation of\nthis mapping and produces the componentFactory.js
output file. We want to use TypeScript for this file because we want the generated import statements also to search for .ts
\nand .tsx
files. must be changed to the .ts
extensions. This means that we need to change\nthe output file to componentFactory.ts
. We also want the component factory generation script\nto pick up .ts
and .tsx
files so components can be written in both JavaScript and TypeScript. This means that we need to add the following lines to the script:
const componentFactoryPath = path.resolve('src/temp/componentFactory.ts');
and
\n fs.existsSync(path.join(componentFolderFullPath, 'index.js')) ||\n fs.existsSync(path.join(componentFolderFullPath, 'index.jsx')) ||\n fs.existsSync(path.join(componentFolderFullPath, 'index.ts')) || fs.existsSync(path.join(componentFolderFullPath, 'index.tsx'))
Rewriting the JSS tool scripts like scripts/generate-component-factory.js
to TypeScript\nas well makes no sense because they are node scripts, and we don’t want to introduce a\ncompilation step in order to run them, although ts-node is a viable solution for directly running TypeScript files in a development environment. Another\nreason is that the JSS tool-set calls these scripts.
On compilation of the componentFactory.ts
file we got the error:
Type error: Could not find a declaration file for module '../components/Hero'. 'C:/P/hello-jss-typescript/src/components/Hero/index.js' implicitly has an 'any' type. TS7016
We got similar errors on more files. The easiest way to resolve this is to set the option\n"noImplicitAny": false
in the tsconfig.json
. This is not a really sustainable option\nbecause using types instead of any
is the whole purpose of using TypeScript, and settings this\noption means that also the application specific code is not checked if types are omitted.
Make sure that you don’t have an old src/temp/componentFactory.js
file because this file will be picked up in the compilation as well.
We can now run jss start
again and get our TypeScript Hero component working in the disconnected site:
\n \n \n \n \n \n \n \n \n \n
Now it’s time to deploy our JSS app to Sitecore as described in\nJSS Server Setup.
\nPart of these steps as described in App Deployment is:
\nhello-jss-typescript.dev.local
127.0.0.1 hello-jss-typescript.dev.local
to the file C:\\Windows\\System32\\drivers\\etc\\hosts
After everything is configured we can run jss setup
and answer the questions (you answers may vary):
Is your Sitecore instance on this machine or accessible via network share? [y/n]: y\nPath to the Sitecore folder (e.g. c:\\inetpub\\wwwroot\\my.siteco.re): c:\\inetpub\\wwwroot\\sc910.sc\nSitecore hostname (e.g. http://myapp.local.siteco.re; see /sitecore/config; ensure added to hosts): http://hello-jss-typescript.dev.local\nSitecore import service URL [http://hello-jss-typescript.dev.local/sitecore/api/jss/import]:\nSitecore API Key (ID of API key item): {57231674-4CC9-48AA-AFF0-190DB9D68FE1}\nPlease enter your deployment secret (32+ random chars; or press enter to generate one):\nDeployment secret has been generated. Ensure the JSS app config on the Sitecore end has the same secret set.\nDeploy secret Sitecore config written to C:\\P\\hello-jss-typescript\\sitecore\\config\\hello-jss-typescript.deploysecret.config\nEnsure this configuration is deployed to Sitecore.\nJSS connection settings saved to C:\\P\\hello-jss-typescript\\scjssconfig.json\n\nNEXT STEPS\n* Ensure the hostName in /sitecore/config/*.config is configured as hello-jss-typescript.dev.local, and in hosts file if needed.\n* Deploy your configuration (i.e. 'jss deploy config')\n* Deploy your app (i.e. 'jss deploy app -c -d')\n* Test your app in integrated mode by visiting http://hello-jss-typescript.dev.local
As specified in the NEXT STEPS
we should deploy the configuration using jss deploy config
\nand deploy the app using jss deploy app -c -d
.
When we deploy the app we get a compilation error in building the server.bundle.js
:
ERROR in ./src/AppRoot.js\nModule not found: Error: Can't resolve './temp/componentFactory' in 'C:\\P\\hello-jss-typescript\\src'\n @ ./src/AppRoot.js 5:0-55 32:22-38\n @ ./server/server.js
Because server/server.js
does an import of AppRoot
from ../src/AppRoot
and\nAppRoot
does an import of ./temp/componentFactory
which is generated as a\nTypeScript file we have an issue. This can be fixed by renaming server/server.js
\nto server/server.tsx
and modifying server/server.webpack.config.js
to have as\nentry entry: path.resolve(__dirname, './server.tsx')
. Because the server bundle specific\nwebpack configuration file does a require of babel-preset-react-app
it can use the\nBabel 7 configuration to compile TypeScript files out of the box.
Next step is to rename the file src/AppRoot.js
to src/AppRoot.tsx
. This is the main\nentry point of the app invoked by the renderer for server and client rendering. It imports\nthe generated src/temp/componentFactory
file, but we can’t import a .ts
file\nfrom a .js
file. It won’t be resolved.
For the Typescript compilation of the server bundle we need the same tsconfig.json
configuration\nas for the client bundle, with only the include path changed. For this we can create the file\nserver/tsconfig
with the following contents:
{\n \"extends\": \"../tsconfig.json\",\n \"include\": [\n \".\"\n ]\n}
Including the content of the above described files will make this blog post too large, so please refer\nto the GitHub repository hello-jss-typescript\nfor the details.
\nIf we now the app using jss deploy app -c -d
we can navigate to http://hello-jss-typescript.dev.local/ and\nthe site is rendered correctly.
The layout of the rendered React page for a given route is provided by the\nSitecore layout service.
\nIn our case a hit on http://hello-jss-typescript.dev.local/sitecore/api/layout/render/jss?item=/&sc_apikey={57231674-4CC9-48AA-AFF0-190DB9D68FE1}
(your API key will vary) gives us:
{\n \"sitecore\": {\n \"context\": {\n \"pageEditing\": false,\n \"site\": {\n \"name\": \"hello-jss-typescript\"\n },\n \"pageState\": \"normal\",\n \"language\": \"en\"\n },\n \"route\": {\n \"name\": \"home\",\n \"displayName\": \"home\",\n \"fields\": {\n \"pageTitle\": {\n \"value\": \"Welcome to Sitecore JSS\"\n }\n },\n \"databaseName\": \"master\",\n \"deviceId\": \"fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3\",\n \"itemId\": \"75b2a549-f227-51dd-98dd-599438514aad\",\n \"itemLanguage\": \"en\",\n \"itemVersion\": 1,\n \"layoutId\": \"a0909742-4629-5ae4-a71a-1fe76a57379a\",\n \"templateId\": \"ab82556d-8208-5edd-a980-be88546ccf5b\",\n \"templateName\": \"App Route\",\n \"placeholders\": {\n \"jss-main\": [\n {\n \"uid\": \"3af894c3-37f9-52fa-943b-561cdf38da1a\",\n \"componentName\": \"Hero\",\n \"dataSource\": \"{0DC131EC-C855-5F8B-BFB9-62606ABB2DF2}\",\n \"fields\": {\n \"heading\": {\n \"value\": \"Serge's hero component!\"\n }\n }\n },\n {\n \"uid\": \"7418112d-b1c0-53fe-9256-b807b16fe3f4\",\n \"componentName\": \"ContentBlock\",\n \"dataSource\": \"{20448A26-84CB-52B7-BCE7-8D4851E8AABC}\",\n \"fields\": {\n \"heading\": {\n \"value\": \"Welcome to Sitecore JSS\"\n },\n \"content\": {\n \"value\": \"<p>Thanks for using JSS. Here are some resources to get you started:</p>\\n\\n<h3><a href=\\\"https://jss.sitecore.net\\\" rel=\\\"noopener noreferrer\\\">Documentation</a></h3>\\n<p>The official JSS documentation can help you with any JSS task from getting started to advanced techniques.</p>\\n\\n<h3><a href=\\\"/styleguide\\\">Styleguide</a></h3>\\n<p>The JSS styleguide is a living example of how to use JSS, hosted right in this app.\\nIt demonstrates most of the common patterns that JSS implementations may need to use,\\nas well as useful architectural patterns.</p>\\n\\n<h3><a href=\\\"/graphql\\\">GraphQL</a></h3>\\n<p>JSS features integration with the Sitecore GraphQL API to enable fetching non-route data from Sitecore - or from other internal backends as an API aggregator or proxy.\\nThis route is a living example of how to use an integrate with GraphQL data in a JSS app.</p>\\n\\n<div class=\\\"alert alert-dark\\\">\\n <h4>This app is a boilerplate</h4>\\n <p>The JSS samples are a boilerplate, not a library. That means that any code in this app is meant for you to own and customize to your own requirements.</p>\\n <p>Want to get change the lint settings? Do it. Want to read manifest data from a MongoDB database? Go for it. This app is yours.</p>\\n</div>\\n\\n<div class=\\\"alert alert-dark\\\">\\n <h4>How to start with an empty app</h4>\\n <p>To remove all of the default sample content (the Styleguide and GraphQL routes) and start out with an empty JSS app:</p>\\n <ol>\\n <li>Delete <code>/src/components/Styleguide*</code> and <code>/src/components/GraphQL*</code></li>\\n <li>Delete <code>/sitecore/definitions/components/Styleguide*</code>, <code>/sitecore/definitions/templates/Styleguide*</code>, and <code>/sitecore/definitions/components/GraphQL*</code></li>\\n <li>Delete <code>/data/component-content/Styleguide</code></li>\\n <li>Delete <code>/data/content/Styleguide</code></li>\\n <li>Delete <code>/data/routes/styleguide</code> and <code>/data/routes/graphql</code></li>\\n <li>Delete <code>/data/dictionary/*.yml</code></li>\\n </ol>\\n</div>\\n\"\n }\n }\n }\n ]\n }\n }\n }\n}
Based on this JSON the final page is built.
\nThis is just the first step… all app specific code must be rewritten in TypeScript. I will keep you posted.
\nInteresting stuff to investigate in this context:
\n","timeToRead":12,"frontmatter":{"title":"Developing React components in Typescript with Sitecore JSS 9.1","date":"January 29, 2019","spoiler":"At my company we use TypeScript for front-end development where possible. In my first steps in using JSS I wanted to build my first component in TypeScript, which did not work out of the box. In this post I describe how I got ypeScript compilation working."},"fields":{"slug":"/sitecore_jss_typescript/"}}},"pageContext":{"slug":"/sitecore_jss_typescript/","previous":{"fields":{"slug":"/weblog-deployment-to-static-azure-website/"},"frontmatter":{"title":"Weblog deployment to a static Microsoft Azure website"}},"next":{"fields":{"slug":"/sitecore_jss_typescript_node/"},"frontmatter":{"title":"Render Sitecore 9.1 JSS site using separate node server"}}}}