How to integrate React in Artanis
GNU Artanis is flexible to support modern web frontend framework. In this article, we will show you how to integrate React in Artanis. Specifically, we will use Typescript in default.
Typescript transpiler is licensed with Apache-2.0 which is compatible with GPL. Although Typescript was dismissed because of the size and little slower performance, the rubustness brought by static typing system should be more important in the development.
Here is an example for Hello World.
We assume that you’re already using Node.js with npm.
For example, you have an Artanis application:
Initialization and dependencies
art create my-test
cd my-test
However, the nodemodules directory can't be put in the toplevel position. You have to initialize your NPM in pub directory:
# In my-test directory cd pub npm init
You’ll be given a series of prompts, but you can feel free to use the defaults. You can always go back and change these in the package.json file that’s been generated for you. If you want to skip those prompts, just type:
npm init -y
We need to install necessary dependencies, however, npm has known issues, let's use yarn instead.
yarn add -D @types/react-dom ts-loader react source-map-loader webpack-bundle-analyzer webpack-manifest-plugin
Please don't install webpack directly, it's already included in webpack-bundle. If you installed webpack directly, there're issues to compile the js code.
Configure Webpack and Typescript
Create and edit tsconfig.json file under pub directory:
{ "compilerOptions": { "outDir": "./pub/js/", "sourceMap": true, "noImplicitAny": true, "module": "commonjs", "target": "es6", "jsx": "react" }, "include": [ "./js/ts/**/*" ], "exclude": ["node_modules"] }
Create and edit webpack.config.js file under the directory which contains a file named ENTRY.
const path = require('path'); const webpack = require('webpack'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); const IS_DEV = (process.env.NODE_ENV === 'development'); module.exports = { mode: 'production', watch: true, entry: { index: "./js/ts/index.tsx", }, output: { filename: IS_DEV ? '[name].bundle.js' : '[name].bundle.[chunkhash].js', path: `${__dirname}/pub/js`, }, // Enable sourcemaps for debugging webpack's output. devtool: "source-map", resolve: { // Add '.ts' and '.tsx' as resolvable extensions. extensions: [".ts", ".tsx", ".js", ".json"] }, plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), 'process.env.BABEL_ENV': JSON.stringify(process.env.BABEL_ENV), }), // Generate a manifest.json for filename entry mappings new WebpackManifestPlugin({ fileName: `${__dirname}/pub/manifest.json`, publicPath: '', // webpack 5 needs to set a default publicPath }), IS_DEV ? new BundleAnalyzerPlugin() : new webpack.DefinePlugin({}), ], optimization: { minimize: !IS_DEV, runtimeChunk: 'single', splitChunks: { cacheGroups: { react: { name: 'react', test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, minChunks: 2, chunks: 'all', }, }, }, } module: { rules: [ // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. { test: /\.tsx?$/, loader: "ts-loader" }, // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. { enforce: "pre", test: /\.js$/, loader: "source-map-loader" } ] }, };
Now let's write some code
Create index.html under pub directory:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> </head> <body> <div id="example"></div> <!-- Main --> <@js runtime.js %> <@js index.js %> </body> </html>
Please notice that we use Artanis specific template syntax <@js runtime.js %> to include runtime.js which is necessary for dependencies include React. This could be further configured in webpack.config.js which is out of topic.
What is Artanis specific template syntax?
Briefly, the syntax is easy to understand.
<@js javascript-filename.js %> <@css css-filename.js %> <@include html-filename.html %> <@icon favicon.png %>
The Artanis template engine will find the related files in specific path, say pub/js for js, pub/css for css, pub/html for html, and pub for icon.
Specifically, the js template will detect manifest.json to find the correct file name for efficent cache. This is out of topic. If you're interested, please refer to the webpack documentation and web frontend best practices.
Typescript code
Please note that js/ts is the directory in the main directory of the project, say the directory contains the file named ENTRY.
Create js/ts/index.tsx under pub directory:
import * as React from "react"; import * as ReactDOM from "react-dom"; import { Hello } from "./components/Hello"; ReactDOM.render( <Hello compiler="TypeScript" framework="React" />, document.getElementById("example") );
Create js/ts/components/Hello.tsx under pub directory:
import * as React from "react"; export interface HelloProps { compiler: string; framework: string; } export const Hello = (props: HelloProps) => <h1>Hello from {props.compiler} and {props.framework}!</h1>;
There're two modes in Webpack: development and production. The bundle will be minimized on production mode only. Let’s add two npm scripts to our package.json to run Webpack:
{ "scripts": { "start": "webpack --mode development", "build": "webpack --mode production" } }
Now, everything is ready, we run webpack to compile Typescript code and pack necessary resources:
yarn build
So webpack is watching your code, anytime you change the code, webpack will automatically update it.
Then, under project folders, open a new terminal, and type:
art work
Hey, don't forget to run art work, the template need to be rendered by Artanis.
OK, now open http://localhost:3000/index.html to see your work.
It's just a Hello World. Feel free to modify it for your cases.
Of course, we put the example project here as a skeleton. You can clone it from here.