Skip to content

Commit

Permalink
refactor(gdpr-cookie-consent): Switch to V2 + Vite (#510)
Browse files Browse the repository at this point in the history
* refactor(gdpr-cookie-consent): Switch to V2 + Vite

* lint

* use useRouteLoaderData instead of useLoaderData, and call it out
  • Loading branch information
machour authored Jun 16, 2024
1 parent 4dea3c4 commit 20116af
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 61 deletions.
84 changes: 84 additions & 0 deletions gdpr-cookie-consent/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* This is intended to be a basic starting point for linting in your app.
* It relies on recommended configs out of the box for simplicity, but you can
* and should modify this configuration to best suit your team's needs.
*/

/** @type {import('eslint').Linter.Config} */
module.exports = {
root: true,
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
env: {
browser: true,
commonjs: true,
es6: true,
},
ignorePatterns: ["!**/.server", "!**/.client"],

// Base config
extends: ["eslint:recommended"],

overrides: [
// React
{
files: ["**/*.{js,jsx,ts,tsx}"],
plugins: ["react", "jsx-a11y"],
extends: [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {},
},
},
},

// Typescript
{
files: ["**/*.{ts,tsx}"],
plugins: ["@typescript-eslint", "import"],
parser: "@typescript-eslint/parser",
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
],
},

// Node
{
files: [".eslintrc.cjs"],
env: {
node: true,
},
},
],
};
4 changes: 0 additions & 4 deletions gdpr-cookie-consent/.eslintrc.js

This file was deleted.

1 change: 0 additions & 1 deletion gdpr-cookie-consent/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ node_modules

/.cache
/build
/public/build
.env
5 changes: 2 additions & 3 deletions gdpr-cookie-consent/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# GDPR Cookie Consent

Create a simple GDPR consent form.
Till the user doesn't click on the `Accept` button, she will see a banner prompting to accept cookies.
Create a simple GDPR consent form, displayed until the button click the `Accept` button.

## Preview

Expand All @@ -14,7 +13,7 @@ Open this example on [CodeSandbox](https://codesandbox.com):
Users will be presented with a GDPR consent form on every page [app/root.tsx](app/root.tsx) till they submit the accept button.
Once they submit the consent form, a dummy tracking [script](public/dummy-analytics-script.js) at the [app/root.tsx](app/root.tsx) will start tracking the user's data (open the browser console too see the dummy tracking message).

> If you want to reset the example delete the `gdpr-consent` cookie in the `Application`/`cookies` in the browser's developer tools.
> If you want to reset the example, delete the `gdpr-consent` cookie in the `Application`/`cookies` in the browser's developer tools.
The example is using [Remix Cookie API](https://remix.run/utils/cookies).

Expand Down
File renamed without changes.
42 changes: 24 additions & 18 deletions gdpr-cookie-consent/app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,53 @@
import type { LoaderArgs, MetaFunction } from "@remix-run/node";
import { json } from "@remix-run/node";
import type { LoaderFunctionArgs } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
json,
useFetcher,
useLoaderData,
useRouteLoaderData,
} from "@remix-run/react";
import * as React from "react";
import { useEffect } from "react";

import { gdprConsent } from "~/cookies";
import { gdprConsent } from "~/cookies.server";

export const loader = async ({ request }: LoaderArgs) => {
export const loader = async ({ request }: LoaderFunctionArgs) => {
const cookieHeader = request.headers.get("Cookie");
const cookie = (await gdprConsent.parse(cookieHeader)) || {};

return json({ track: cookie.gdprConsent });
};

export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
});
export function Layout({ children }: { children: React.ReactNode }) {
// We use `useRouteLoaderData` here instead of `useLoaderData` because
// the <Layout /> component will also be used by the <ErrorBoundary />
// if an error is thrown somewhere in the app, and we can't call
// `useLoaderData()` while rendering an <ErrorBoundary />.
const rootLoaderData = useRouteLoaderData<{ track?: true }>("root");
const track = rootLoaderData?.track ?? false;

export default function App() {
const { track } = useLoaderData<typeof loader>();
const analyticsFetcher = useFetcher();
React.useEffect(() => {
useEffect(() => {
if (track) {
const script = document.createElement("script");
script.src = "/dummy-analytics-script.js";
document.body.append(script);
}
}, [track]);

const analyticsFetcher = useFetcher();

return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
{children}
{track ? null : (
<div
style={{
Expand All @@ -64,8 +67,11 @@ export default function App() {
)}
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

export default function App() {
return <Outlet />;
}
6 changes: 3 additions & 3 deletions gdpr-cookie-consent/app/routes/enable-analytics.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { ActionArgs } from "@remix-run/node";
import type { ActionFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";

import { gdprConsent } from "~/cookies";
import { gdprConsent } from "~/cookies.server";

export const action = async ({ request }: ActionArgs) => {
export const action = async ({ request }: ActionFunctionArgs) => {
const formData = await request.formData();
const cookieHeader = request.headers.get("Cookie");
const cookie = (await gdprConsent.parse(cookieHeader)) || {};
Expand Down
39 changes: 25 additions & 14 deletions gdpr-cookie-consent/package.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
{
"name": "gdpr-cookie-consent",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"build": "remix build",
"dev": "remix dev",
"start": "remix-serve build",
"build": "remix vite:build",
"dev": "remix vite:dev",
"lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
"start": "remix-serve ./build/server/index.js",
"typecheck": "tsc"
},
"dependencies": {
"@remix-run/node": "^1.19.3",
"@remix-run/react": "^1.19.3",
"@remix-run/serve": "^1.19.3",
"isbot": "^3.6.5",
"@remix-run/node": "^2.9.2",
"@remix-run/react": "^2.9.2",
"@remix-run/serve": "^2.9.2",
"isbot": "^4.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^1.19.3",
"@remix-run/eslint-config": "^1.19.3",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"eslint": "^8.27.0",
"typescript": "^4.8.4"
"@remix-run/dev": "^2.9.2",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"eslint": "^8.38.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"typescript": "^5.1.6",
"vite": "^5.1.0",
"vite-tsconfig-paths": "^4.2.1"
},
"engines": {
"node": ">=14.0.0"
"node": ">=20.0.0"
}
}
11 changes: 0 additions & 11 deletions gdpr-cookie-consent/remix.config.js

This file was deleted.

2 changes: 0 additions & 2 deletions gdpr-cookie-consent/remix.env.d.ts

This file was deleted.

20 changes: 15 additions & 5 deletions gdpr-cookie-consent/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
{
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
"include": [
"**/*.ts",
"**/*.tsx",
"**/.server/**/*.ts",
"**/.server/**/*.tsx",
"**/.client/**/*.ts",
"**/.client/**/*.tsx"
],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": ["@remix-run/node", "vite/client"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2019",
"target": "ES2022",
"strict": true,
"allowJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},

// Remix takes care of building everything in `remix build`.
// Vite takes care of building everything, not tsc.
"noEmit": true
}
}
16 changes: 16 additions & 0 deletions gdpr-cookie-consent/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
plugins: [
remix({
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true,
},
}),
tsconfigPaths(),
],
});

0 comments on commit 20116af

Please sign in to comment.