Check out the demo at /apps/web
Importing a file with createInlineScript
// index.tsx
import Head from "next/head";
import { createInlineScript } from "next-inline-script";
const HelloWorld = createInlineScript(import("./helloWorld"));
export default function Page() {
return (
<>
<h1>Next Inline Script Demo</h1>
<Head>
<HelloWorld message="hello my message" />
</Head>
</>
);
}
which exports a function that can take props
// helloWorld.ts
export default function helloWorld(props: { message: string }): void {
console.log(props.message);
}
will compile helloWorld.ts
and render it inline in the <head>
section of your document
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta charset="utf-8" />
<script>
(function helloWorld(props) {
console.log(props.message);
})({ message: "hello my message" });
</script>
</head>
<body></body>
</html>
This code gets executed before react or next js has loaded. It is not a silver bullet, inline JavaScript is render blocking, but there are situations where this is critical. With this plugin you get a tool to design your loading strategy and an execution order.
- You need to initialize (complex) third party code
- You need exucute code with high priority
- You need to run code synchronously
Using next js' built inline script features, you need to write code as a string, which makes debugging and testing really difficult. Using this plugin you get full IDE and TS integration, including type-safety of the props of the generated React component and its data.
- uses code splitting to separate your inline code from your main bundle, so your main bundle will not grow in size
- uses next's compiler with all its settings. Any plugin you use will also be available in the inline code
- code will be rendered at compile time, props will be injected at run time, so you can use dynamic data in your inline code
- testing with jest is completely possible, but I still need to document it
Add next-inline-script/plugin
to your next config
// next.config.js
const withCompileToString = require("next-inline-script/plugin");
module.exports = withCompileToString({
reactStrictMode: true,
});
Create a file that exports a function as default
// myScript.ts
export default function myScript(props: { message: string }): void {
console.log(props.message);
}
Anywhere in your next js project pass an import statement to createInlineScript
to create a react Component
that will render the compiled source of that file in a <script>
tag.
import { createInlineScript } from "next-inline-script";
const MyScript = createInlineScript(import("./myScript"));
const MyComponent = () => <MyScript message="my message" />;
Rendering <MyScript message="my message" />
will give you this code:
<script>
(function myScript(props) {
console.log(props.message);
})({ message: "hello my message" });
</script>
Your code will get transpiled and inlined and the props of the JSX declaration (message="my message"
) will
be stringified using JSON.stringify
and passed to your function.
This means any data that can be serialized with JSON.stringify
can be passed to the your code.
Your code will be transpiled at compile time
(function myScript(props) {
console.log(props.message);
});
but the props will get rendered at run time
(/* function myScript(props) {
console.log(props.message);
} */)({ message: "hello my message" });
This has a big advantage:
Lets say you need to initialze some third party library, like ads, tracking or consent. For the initilization you often need to use data that you do not know at compile time, but only at run time. By passing in that data as props instead of hard-coded values in your script, you can have your cake and eat it too!
You need to pass an import statement to the createInlineScript
function. This is to enable IDE and TS support,
but this also comes with an obligation to do this, you can't just us a path as a string, for instance.
You also need a default export which has to be a function. This issue can be resolved, which will happen at some point.
While this repo does not contain unit-tests yet, this plugin is implicitly unit-tested and battle tested at t-online.de, Germany's largest news website with millions of users. A test suit will follow as I complete the library.