handoff-app
Version:
Automated documentation toolchain for building client side documentation from figma
158 lines (149 loc) • 5.05 kB
JavaScript
import mdx from '@next/mdx';
import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';
import { visit } from 'unist-util-visit';
const CodeTransform = () => {
return (tree, file) => {
visit(tree, 'code', (node, index, parent) => {
const metaString = `${node.lang ?? ''} ${node.meta ?? ''}`.trim();
const props = { col: '12', codetitle: '' };
if (!metaString) return;
const [col] = metaString.match(/(?<=col=("|'))(.*?)(?=("|'))/) ?? [''];
if (col) {
props.col = col;
}
const [title] = metaString.match(/(?<=title=("|'))(.*?)(?=("|'))/) ?? [''];
if (!title && metaString.includes('title=')) {
file.message('Invalid title', node, 'remark-code-title');
return;
}
if (!title) return;
props.codetitle = [title];
// @ts-ignore
//node.data = title;
node.data = { hProperties: props };
return index ? index + 2 : 0;
});
};
};
const withMDX = mdx({
options: {
remarkPlugins: [CodeTransform],
rehypePlugins: [],
},
});
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
reactStrictMode: true,
// Configure `pageExtensions` to include MDX files
pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
trailingSlash: true,
experimental: {
externalDir: true,
},
eslint: {
dirs: ['pages', 'utils'],
},
transpilePackages: ['handoff-app', 'react-syntax-highlighter'],
typescript: {
tsconfigPath: 'tsconfig.json',
},
distDir: 'out',
basePath: '',
env: {
HANDOFF_PROJECT_ID: '',
HANDOFF_APP_BASE_PATH: '',
HANDOFF_WORKING_PATH: '',
HANDOFF_MODULE_PATH: '',
HANDOFF_EXPORT_PATH: '',
HANDOFF_WEBSOCKET_PORT: '',
},
serverRuntimeConfig: {
PROJECT_ROOT: path.resolve('public'),
},
images: {
unoptimized: true,
},
sassOptions: {
additionalData: (content, _) => {
// Local state
let foundTheme = false;
// Local environment
const env = {
HANDOFF_PROJECT_ID: '',
HANDOFF_APP_BASE_PATH: '',
HANDOFF_WORKING_PATH: '',
HANDOFF_MODULE_PATH: '',
HANDOFF_EXPORT_PATH: '',
HANDOFF_WEBSOCKET_PORT: '',
};
// Check if client configuration exists
const clientConfigPath = path.resolve(env.HANDOFF_WORKING_PATH, 'handoff.config.json');
if (fs.existsSync(clientConfigPath)) {
// Load client configuration
const clientConfigRaw = fs.readFileSync(clientConfigPath);
const clientConfig = JSON.parse(clientConfigRaw);
// Check if client configuration is a valid object
if (typeof clientConfig === 'object' && !Array.isArray(clientConfig) && clientConfig !== null) {
// Check if the client configuration specifies a theme
// If the theme is specified, check if the theme exists in the 'themes' folder
if (
clientConfig.hasOwnProperty('app') &&
clientConfig['app'].hasOwnProperty('theme') &&
fs.existsSync(path.resolve(env.HANDOFF_WORKING_PATH, 'theme', `${clientConfig['app']['theme']}.scss`))
) {
// Use custom theme
foundTheme = true;
content = content + `\n@import '${path.resolve(env.HANDOFF_WORKING_PATH, 'theme', clientConfig['app']['theme'])}';`;
console.log(
`- ${chalk.cyan('info')} Using custom app theme (name: ${clientConfig['app']['theme']}, path: ${path.resolve(
env.HANDOFF_WORKING_PATH,
'theme',
clientConfig['app']['theme']
)}.scss)`
);
}
}
}
if (!foundTheme) {
// Check if there is a custom version of the default theme
if (fs.existsSync(path.resolve(env.HANDOFF_WORKING_PATH, 'theme', `default.scss`))) {
// Use custom theme
content = content + `\n@import 'theme/default';`;
console.log(
`- ${chalk.cyan('info')} Using default app theme override (path: ${path.resolve(
env.HANDOFF_WORKING_PATH,
'theme',
`default.scss`
)})`
);
} else {
// Use default theme
content = content + `\n@import 'themes/default';`;
console.log(`- ${chalk.cyan('info')} Using default app theme`);
}
}
return content;
},
},
webpack: (config) => {
config.resolve.fallback = { fs: false };
config.resolve.alias['@handoff'] = path.resolve('%HANDOFF_MODULE_PATH%/src');
config.resolve.modules.push(path.resolve('dist/app'));
config.resolve.modules.push(path.resolve('node_modules'));
config.resolveLoader.modules.push(path.resolve('node_modules'));
config.module.rules.push({
test: /\.svg$/i,
type: 'asset',
});
config.module.rules.push({
test: /\.html$/i,
loader: 'html-loader',
});
return config;
},
};
// Wrap MDX and Next.js config with each other
export default withMDX(nextConfig);