permalinkUsing the 'use client' directive

When you do anything in your components that requires state they can't be rendered on the server. This is because the server doesn't have access to the state of your app. This is where the use client directive comes in. It allows you to tell your components that they should only be rendered on the client.

It has a weird syntax however which is a string at the top of the file just saying 'use client'. It's surprisingly difficult to produce this string with PureScript but here's how I do it:

permalinkCompile your PureScript with the --comments flag

Here's an excerpt from my package.json:

package.json
{
  "scripts": {
    "build:spago": "spago build --purs-args \"-c\""
  }
}

This tells the compiler to leave any comments inside your code untouched.

permalinkUse a comment to produce the 'use client' string

Here's an example of a component that uses the 'use client' directive:

Container.purs
-- use client
module Container (default) where

import Prelude
import React.Basic.Hooks as React
import React.Basic (JSX, ReactComponent, fragment)
import React.Basic.Hooks (ReactChildren, reactChildrenToArray)
import Effect.Unsafe (unsafePerformEffect)
import React.Basic.DOM (text)

default :: ReactComponent { children :: ReactChildren JSX }
default = unsafePerformEffect $ React.reactComponentWithChildren "Container" \props -> React.do
  let children = reactChildrenToArray props.children
  state /\ setState <- React.useState 0
  pure $ fragment [ children, text state ]

It's important to use unsafePerformEffect here because Next.js will check for actual ReactComponents in the file. It's perfectly fine to use unsafePerformEffect at the top level of your files.

permalinkUse a webpack loader to transform the comment into the directive

Install it first:

install
npm install --save-dev string-replace-loader
next.config.js
module.exports = {
    experimental: {appDir: true},

    webpack: config => {
        config.module.rules.push({
                test: /index\.js$/,
                loader: 'string-replace-loader',
                options: {
                    search: '// use client',
                    replace: '"use client";'
                }
            },
            {
                test: /\.purs/, type: 'asset/source',
            }
        )
        return config
    }
}

There's the string-replace-loader which will replace the comment with the directive in all of our files PureScript files.

The good thing is that purs-ide leaves the comments alone, so you can still use it to develop your PureScript code. Just make sure that you use npm run build:spago and not spago build to build your PureScript code.

And use server?
You can add an equivalent rule for use server