react-static
Version:
A progressive static site generator for React
223 lines (201 loc) • 5.63 kB
JavaScript
import axios from 'axios'
import React, { Component } from 'react'
import { ServerStyleSheet } from 'styled-components'
/*
* For Less Support
* */
import autoprefixer from 'autoprefixer'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
import postcssFlexbugsFixes from 'postcss-flexbugs-fixes'
/*
* For TypeScript Support
* */
const typescriptWebpackPaths = require('./webpack.config.js')
const path = require('path')
const fs = require('fs')
const lessToJs = require('less-vars-to-js')
const themeVariables = lessToJs(fs.readFileSync(path.join(__dirname, 'src/theme-ant-overwrite.less'), 'utf8'))
const webpack = require('webpack')
//
export default {
getSiteData: () => ({
title: 'React Static',
}),
getRoutes: async () => {
const { data: posts } = await axios.get('https://jsonplaceholder.typicode.com/posts')
return [
{
path: '/',
component: 'src/containers/Home',
},
{
path: '/about',
component: 'src/containers/About',
},
{
path: '/blog',
component: 'src/containers/Blog',
getData: () => ({
posts,
}),
children: posts.map(post => ({
path: `/post/${post.id}`,
component: 'src/containers/Post',
getData: () => ({
post,
}),
})),
},
{
is404: true,
component: 'src/containers/404',
},
]
},
renderToHtml: (render, Comp, meta) => {
const sheet = new ServerStyleSheet()
const html = render(sheet.collectStyles(<Comp />))
meta.styleTags = sheet.getStyleElement()
return html
},
Document: class CustomHtml extends Component {
render () {
const {
Html, Head, Body, children, renderMeta,
} = this.props
return (
<Html>
<Head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{renderMeta.styleTags}
</Head>
<Body>
{children}
</Body>
</Html>
)
}
},
webpack: (config, { stage, defaultLoaders }) => {
/*
* TypeScript Support
* */
// Add .ts and .tsx extension to resolver
config.resolve.extensions.push('.ts', '.tsx')
// Add TypeScript Path Mappings (from tsconfig via webpack.config.js)
// to react-statics alias resolution
config.resolve.alias = typescriptWebpackPaths.resolve.alias
// Needed for momoent js resolution in React 16
// See: https://github.com/moment/moment/issues/2979#issuecomment-332217206
config.resolve.alias.moment$ = 'moment/moment.js'
// We replace the existing JS rule with one, that allows us to use
// both TypeScript and JavaScript interchangeably
const jsTsLoader = {
test: /\.(js|jsx|ts|tsx)$/,
exclude: defaultLoaders.jsLoader.exclude, // as std jsLoader exclude
use: [
{
loader: 'babel-loader',
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
}
/*
* Less Support
* */
// Add .less & .css to resolver
config.resolve.extensions.push('.less')
config.resolve.extensions.push('.css')
// Loader depending on stage. Same format as the default cssLoader.
let loaders = [
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: stage !== 'dev',
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
sourceMap: true,
ident: 'postcss',
plugins: () => [
postcssFlexbugsFixes,
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
{
loader: 'less-loader',
options: {
sourceMap: true,
modifyVars: themeVariables,
javascriptEnabled: true,
},
},
]
if (stage === 'dev') {
// Enable Hot Module Replacement
config.plugins.push(new webpack.HotModuleReplacementPlugin())
// In-Line with style-loader
loaders = ['style-loader'].concat(loaders)
} else if (stage === 'prod') {
// Extract to style.css
loaders = ExtractTextPlugin.extract({
fallback: {
loader: 'style-loader',
options: {
hmr: false,
sourceMap: false,
},
},
use: loaders,
})
}
const lessLoader = {
test: /\.less$/,
use: loaders,
}
/*
* Add new Loaders to default Loaders
* */
config.module.rules = [
{
oneOf: [jsTsLoader, lessLoader, defaultLoaders.cssLoader, defaultLoaders.fileLoader],
},
]
if (stage === 'prod') {
// Update ExtractTextPlugin with current instance
config.plugins.forEach((plugin, index) => {
if (plugin instanceof ExtractTextPlugin) {
config.plugins[index] = new ExtractTextPlugin({
filename: getPath => {
process.env.extractedCSSpath = 'styles.css'
return getPath('styles.css')
},
allChunks: true,
})
}
})
}
return config
},
}