Skip to content
This repository was archived by the owner on May 4, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@babel/preset-flow"
],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
["babel-plugin-react-rename", {
"only": "./src/component/**/*.js",
"rename": "./config/babel/getComponentName.babel.js"
Expand Down
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ globals:
module: true
require: true
process: true
global: true
14 changes: 11 additions & 3 deletions config/webpack/client.babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import base from './partial/base';

const getRender = () => {
try {
return require('../../dist/render').default;
return require('../../dist/render');
} catch (err) {
console.log('Unable to load static page renderer.');
console.log('Make sure you built the renderer first.');
Expand All @@ -23,13 +23,21 @@ const createConfig = compose(
name: 'html/[path][name].[ext]',
paths: [
'/',
'/error/404',
'/error/500',
],
mapStatsToProps: (stats) => {
return {stats};
},
render: getRender(),
render: (props) => {
const render = getRender();
if (props.path === '/error/500') {
return render.renderError({
...props,
error: new Error(),
});
}
return render.renderApp(props);
},
}), config);
},
output({
Expand Down
54 changes: 54 additions & 0 deletions config/webpack/partial/babel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import path from 'path';
import fs from 'fs';
import {loader} from 'webpack-partial';
import {map} from 'ramda';

const getTargets = (target) => {
switch (target) {
case 'node':
return {node: 'current'};
case 'web':
default:
return undefined;
}
};

export default () => (config) => {
const babelConfig = JSON.parse(fs.readFileSync(path.join(
config.context,
'.babelrc',
)));
const target = config.target;
return loader({
loader: 'babel-loader',
include: [
path.join(config.context, 'src'),
path.join(config.context, 'lib'),
],
test: /\.js$/,
options: {
...babelConfig,
presets: map((entry) => {
const [name, config] = Array.isArray(entry) ?
entry : [entry, {}];
if (name === '@babel/preset-env') {
return [name, {
...config,
modules: false,
useBuiltIns: 'usage',
ignoreBrowserslistConfig: target === 'node',
targets: getTargets(target),
include: [
...(config.include || []),
// While newer versions of node support this, `webpack` does
// not because it uses `acorn`. So adjust accordingly.s
'proposal-object-rest-spread',
],
}];
}
return entry;
}, babelConfig.presets),
cacheDirectory: false,
},
}, config);
};
56 changes: 8 additions & 48 deletions config/webpack/partial/base.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,26 @@
import {compose, assoc, identity, map} from 'ramda';
import {compose, assoc, identity} from 'ramda';
import nearest from 'find-nearest-file';
import path from 'path';
import webpack from 'webpack';
import fs from 'fs';

import {output, loader, plugin} from 'webpack-partial';
import {output, plugin} from 'webpack-partial';

// import env from 'webpack-config-env';
// import css from './css';
// import icon from './icon';
// import image from './image';
import babel from './babel';
import intl from './intl';

import CleanPlugin from 'clean-webpack-plugin';
import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
import StatsPlugin from 'stats-webpack-plugin';

const context = path.dirname(nearest('package.json'));
const babelConfig = JSON.parse(fs.readFileSync(path.join(context, '.babelrc')));

const isProduction = process.env.NODE_ENV === 'production';
const isDev = !process.env.NODE_ENV || process.env.NODE_ENV === 'development';

const getTargets = (target) => {
switch (target) {
case 'node':
return {node: 'current'};
case 'web':
default:
return undefined;
}
};

const base = ({name, target}) => compose(
(config) => plugin(new CleanPlugin([config.output.path], {
root: config.context,
Expand All @@ -49,38 +39,8 @@ const base = ({name, target}) => compose(
NODE_ENV: {required: false},
}),*/

(config) => loader({
loader: 'babel-loader',
include: [
path.join(config.context, 'src'),
path.join(config.context, 'lib'),
],
test: /\.js$/,
options: {
...babelConfig,
presets: map((entry) => {
const [name, config] = Array.isArray(entry) ?
entry : [entry, {}];
if (name === '@babel/preset-env') {
return [name, {
...config,
modules: false,
useBuiltIns: 'usage',
ignoreBrowserslistConfig: target === 'node',
targets: getTargets(target),
include: [
...(config.include || []),
// While newer versions of node support this, `webpack` does
// not because it uses `acorn`. So adjust accordingly.s
'proposal-object-rest-spread',
],
}];
}
return entry;
}, babelConfig.presets),
cacheDirectory: false,
},
}, config),
babel(),
intl(),

// icon(),
// image(),
Expand Down Expand Up @@ -122,10 +82,10 @@ const base = ({name, target}) => compose(
path: path.join(context, 'dist', name),
...isProduction && target === 'web' ? {
filename: '[name].[chunkhash].js',
chunkFilename: '[id].[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js',
} : {
filename: '[name].js',
chunkFilename: '[id].[name].js',
chunkFilename: '[name].js',
},
}),

Expand Down
75 changes: 75 additions & 0 deletions config/webpack/partial/intl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {join, isAbsolute} from 'path';
import fs from 'fs';

import {pipe, uniq, map, filter, concat} from 'ramda';
import compact from 'lodash/fp/compact';

import chalk from 'chalk';
import {ContextReplacementPlugin} from 'webpack';
import {plugin, alias, loader} from 'webpack-partial';
import localeEmoji from 'locale-emoji';

export default ({messagesDir = 'intl/messages'} = {}) => (config) => {
const messagesDirPath = isAbsolute(messagesDir)
? messagesDir
: join(config.context, messagesDir);

// Infer the current available locales from the names of the files within the
// `/locale` directory. This way the current locales are automatically parsed
// and can be referenced from within the build.
const localeFiles = filter((name) => {
return /^[a-z]{2}(-[a-z0-9]{2})?\..*$/i.test(name);
}, fs.readdirSync(messagesDirPath));

const locales = pipe(
map((file) => {
return /^[a-z]{2}(-[a-z0-9]{2})?/i.exec(file)[0];
}),
concat(['en-US']),
uniq,
)(localeFiles);

// Define a default locale, use the env `DEFAULT_LOCALE` if it is among the
// parsed available locales, otherwise fall back to the default `en`.
// const defaultLocale = find(eq(process.env.DEFAULT_LOCALE), locales)
// || locales[0];

// Parse the current languages from the current locales by removing the
// country codes from the locale identifiers. React intl locale-data polyfill
// modules are defined only by language, not country as well.
const languages = pipe(map((locale) => locale.split('-')[0]), uniq)(locales);

// React intl bundles `en` language data by default, so we never want to
// include id separately.
// const reactIntlLanguages = reject(eq('en'), languages);

console.log(`🌐 ${chalk.bold('Build Locales')}\n${pipe(
map((locale) => ` ${locale} ${localeEmoji(locale)}`),
compact,
uniq,
)(locales).join('\n')}`);

return pipe(
// Alias React Intl and Intl to versions that do not bundle all locale
// data by default.
alias('react-intl$', require.resolve('react-intl/dist/react-intl.js')),
alias('intl$', require.resolve('intl/lib/core.js')),
plugin(new ContextReplacementPlugin(/^react-intl\/locale-data/, (x) => {
x.regExp = new RegExp(languages.join('|'));
x.chunkName = 'intl-react-[request]';
})),
plugin(new ContextReplacementPlugin(/^intl\/locale-data/, (x) => {
x.regExp = new RegExp(locales.join('|'));
x.chunkName = 'intl-polyfill-[request]';
})),
plugin(new ContextReplacementPlugin(/intl\/messages/, (x) => {
x.regExp = new RegExp(locales.join('|'));
x.chunkName = 'intl-messages-[request]';
console.log(x);
})),
loader({
test: /intl\/messages\//,
loader: ['json-loader', 'yaml-loader'],
})
)(config);
};
56 changes: 56 additions & 0 deletions intl/generateLocaleFiles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* eslint-disable no-console */
import {transformFile} from '@babel/core';
import glob from 'glob';
import fs from 'fs';

const config = JSON.parse(fs.readFileSync('.babelrc'));

const options = {
...config,
plugins: [
'react-intl',
...config.plugins,
],
};

const messages = [];

const processMessages = (x) => {
messages.push(...x);
};

const done = () => {
const data = messages.map(({description, id, defaultMessage}) => {
return [
`# ${description}`,
`${id}: ${defaultMessage}`,
].join('\n');
}).join('\n\n');

fs.writeFileSync(
'./intl/messages/default.yml',
data,
);
};

glob('./src/component/**/*.js', (err, matches) => {
if (err) {
console.error(err);
process.exit(1);
}
let count = matches.length;
matches.forEach((file) => {
transformFile(file, options, (err, result) => {
--count;
if (!err) {
processMessages(result.metadata['react-intl'].messages.map((x) => ({
...x,
file,
})));
}
if (count === 0) {
done();
}
});
});
});
2 changes: 2 additions & 0 deletions intl/messages/default.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# undefined
some message: Hello World
1 change: 1 addition & 0 deletions intl/messages/en-CA.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
some message: Hello World
Loading