reactjs - Sätt upp react-styleguidist, Create React App, Typescript, Material UI och styled-components
Jag försöker sätta upp react-styleguidist (RSG) från Create React App 3 (CRA), Typescript, Material UI och styled-components. Jag fastnade på det här felet:
./node_modules/react-styleguidist/lib/client/rsg-components/ReactExample/ReactExample.js
Module not found: Can't resolve 'rsg-components/Wrapper' in '/Users/ofj/code/new-core-web/node_modules/react-styleguidist/lib/client/rsg-components/ReactExample'
Jag följde dokumentationen för att sätta upp wrappers för MUI-tema och styled-components:
https://react-styleguidist.js.org/docs/thirdparties.html#styled-components
/styleguidist/MuiThemeWrapper.tsx
const muiTheme = getMuiTheme({});
const MuiThemeWrapper = ({ children, ...rest }) => (
<MuiThemeProvider muiTheme={muiTheme}>
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
</MuiThemeProvider>
);
export default MuiThemeWrapper;
Min styleguidist-konfiguration:
/styleguidist.config.js
const path = require('path');
module.exports = {
components: "src/components/**/layout.{js,jsx,ts,tsx}",
propsParser: require('react-docgen-typescript').withCustomConfig(
'./tsconfig.json'
).parse,
serverPort: 6161,
styleguideComponents: {
Wrapper: path.join(__dirname, 'styleguidist/MuiThemeWrapper.jsx')
}
};
Min tsconfig följer standardrekommendationer för CRA/MUI
https://material-ui.com/guides/typescript/
tsconfig.json
{
"compilerOptions": {
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"baseUrl": "src",
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"checkJs": false,
"pretty": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"exclude": [
"node_modules"
],
"types": [
"./node_modules/@types/"
]
}
Jag har ingen anpassad webpack/babel-konfiguration eftersom jag inte vet hur och inte vill förstöra TS-transpileringen. Kanske är detta vad som saknas för att RSG ska fungera...? Eller är felet med rsg-components/ReactExample/ReactExample.js en bugg?
Svar #1
Jag fick det att fungera och förhoppningsvis kan andra också tycka att detta är användbart, eftersom det hittills finns få och endast icke-Typescript-exempelkonfigurationer att hitta.
Saker att notera för min uppsättning:
- react mui-appen finns i
src/, komponenter finns isrc/components/, och använder enmodules:webpack-konfiguration för att leta isrc/för absoluta importer. - appen har skapats med hjälp av React app-skaparen.
tsconfig.jsonautogenererad (ändrarnoEmitsenare specifikt för endast "ts-loader", se nedan); det finns ett viktigt undantag/tillägg som visas nedan.- inga separata webpack- och babel-konfigurationer, inkluderade i
styleguide.config.js.
tsconfig.json är standard, förutom denna pärla paths:'rsg-components/*' här, som måste läggas till manuellt -- den är dold i React Styleguidists Cookbook. Utan den måste vi använda aliasdefinitioner i webpack-konfigurationen, även för att ersätta wrapper! Med korrekt paths-definition i tsconfig.json börjar saker äntligen falla på plats.
{
"compilerOptions": {
"paths": {
"rsg-components/*": [
"node_modules/react-styleguidist/lib/client/rsg-components/*"
]
}
}
}
styleguide.config.js finns i projektets toppnivåkatalog:
const path = require('path')
module.exports = {
components: [
'src/components/**/*.{ts,tsx}',
'src/models/**/*.ts',
],
ignore: [
'src/**/index.{ts,tsx}',
],
// We need to override how to decide on what an example file is, in order
// to remove default which tries to document undocumented components. Ugh.
// So, only document components for which we also have an explicit
// documentation file named the same as the component file, but ending in
// ".md" instead.
getExampleFilename: (cpath) => {
return cpath.replace(/\.(tsx?)$/, '.md')
},
// Show import commands without the component filename extension and only
// for the module; also remove the first "src/" path component.
getComponentPathLine: (cpath) => {
const cname = ['.tsx', '.ts'].reduce((name, ext) => path.basename(name, ext), cpath)
const cdir = path.dirname(cpath).replace(/^src\//, '')
return `import { ${cname} } from ${cdir}`
},
// How uncivilized: do not list components lacking an example.
skipComponentsWithoutExample: true,
// Always expand the props and methods of components.
usageMode: 'expand',
// Support rendering prop types of typescript components.
propsParser: require('react-docgen-typescript').withCustomConfig(
'./tsconfig.json',
{
"compilerOptions": { "noEmit": false },
}
).parse,
// Replace the standard wrapper for example component usage code with our
// own wrapper which brings in the Material UI theme.
styleguideComponents: {
Wrapper: path.join(__dirname, 'styleguidist/MuiThemeWrapper.tsx')
},
// Tell webpack what to look for and where and how to load it.
webpackConfig: {
resolve: {
extensions: ['.tsx', '.ts', '.js'],
// https://webpack.js.org/configuration/resolve/#resolvemodules;
// we're allowing absolute imports to be satisfied from the src/
// directory.
modules: [
path.resolve(__dirname, 'src/'),
'node_modules'
],
alias: {
// Could also be covered by a modules clause, but we are
// sticking with an alias instead to cover only exactly
// absolute "styleguidist/..." imports.
'styleguidist': path.join(__dirname, 'styleguidist'),
}
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
"@babel/preset-env",
"@babel/react",
]
},
},
{
loader: 'ts-loader',
options: {
// Important! Avoids "Error: TypeScript emitted no output for..." errors
compilerOptions: {
noEmit: false,
},
},
},
],
},
{
test: /\.css$/,
loader: 'style-loader!css-loader?modules',
},
{
test: /\.svg$/,
loader: 'url-loader',
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/',
}
},
]
}
]
},
}
}
- att täcka
styleguidist/absoluta importer kunde täckas medmodules:-klasulen, men i det här fallet valde jag istället en alias. Du kanske bedömer detta annorlunda :) - Jag sätter upp ett ganska restriktivt system för att dokumentera endast komponenter med exempel; bli av med det om du inte vill ha det.
- Svårigheterna ligger i att konfigurera webpack med rätt loaders; jag har aktiverat TypeScript, TSX och JSX, samt hämtar in fontresurser.
- Viktigt: wrappern finns i
styleguidist/MuiThemeWrapper.tsx.
Och det är min wrapper styleguidist/MuiThemeWrapper.tsx:
(för MUI v5, se svaret på MUI v5 + React styleguidist + ScopedCSSBaseline + createTheme styleOverrides: ändring av kroppens fontstorlek fungerar inte)
import React from 'react'
import "fontsource-roboto/400.css"
import "fontsource-roboto/500.css"
import "fontsource-roboto/700.css"
import "fontsource-roboto-mono/400.css"
import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'
import CssBaseline from '@material-ui/core/CssBaseline'
const muiTheme = createMuiTheme({})
const MuiThemeWrapper = ({children}) => (
<ThemeProvider theme={muiTheme}>
<CssBaseline />
{children}
</ThemeProvider>
)
export default MuiThemeWrapper
- explicit drar in de Roboto-typsnitt jag behöver i mitt react+Material UI-projekt.
- tillämpa CSS-baslinjedefinitionen, annars kommer
font-familyinte att definieras korrekt.
