@datawheel/canon-core
Version:
Reusable React environment and components for creating visualization engines.
153 lines (135 loc) • 4.34 kB
JavaScript
const MiniCssExtractPlugin = require("mini-css-extract-plugin"),
fs = require("fs"),
path = require("path"),
rootDir = process.cwd();
const postCSSPath = require.resolve("./postcss");
delete require.cache[postCSSPath];
const postCSS = require(postCSSPath);
module.exports = commonLoaders;
/**
* @param {object} props
* @param {boolean} props.extract
* @param {boolean} props.server
* @param {"development" | "production"} props.mode
*/
function commonLoaders(props) {
props = Object.assign({
extract: false
}, props);
const production = props.mode === "production";
const cssLoaders = [{
loader: "css-loader",
options: {
modules: "global",
sourceMap: !production
}
}, {
loader: "postcss-loader",
options: {
plugins: postCSS,
sourceMap: !production
}
}];
const babelPresets = [
[require.resolve("@babel/preset-env"), {
modules: false,
forceAllTransforms: true
}],
require.resolve("@babel/preset-react")
];
const babelPlugins = [
// Stage 0
require.resolve("@babel/plugin-proposal-function-bind"),
// Stage 1
require.resolve("@babel/plugin-proposal-export-default-from"),
require.resolve("@babel/plugin-proposal-logical-assignment-operators"),
[require.resolve("@babel/plugin-proposal-optional-chaining"), {loose: false}],
[require.resolve("@babel/plugin-proposal-pipeline-operator"), {proposal: "minimal"}],
[require.resolve("@babel/plugin-proposal-nullish-coalescing-operator"), {loose: false}],
require.resolve("@babel/plugin-proposal-do-expressions"),
// Stage 2
[require.resolve("@babel/plugin-proposal-decorators"), {legacy: true}],
require.resolve("@babel/plugin-proposal-function-sent"),
require.resolve("@babel/plugin-proposal-export-namespace-from"),
require.resolve("@babel/plugin-proposal-numeric-separator"),
require.resolve("@babel/plugin-proposal-throw-expressions"),
// Stage 3
require.resolve("@babel/plugin-syntax-dynamic-import"),
require.resolve("@babel/plugin-syntax-import-meta"),
[require.resolve("@babel/plugin-proposal-class-properties"), {loose: false}],
require.resolve("@babel/plugin-proposal-json-strings"),
// React specific
require.resolve("@babel/plugin-transform-react-constant-elements")
];
if (production) {
babelPlugins.push(
require.resolve("@loadable/babel-plugin") // detects functional import() statements for code-splitting
);
}
else {
if (!props.server) {
babelPlugins.push(
require.resolve("react-refresh/babel")
);
}
babelPlugins.push(
require.resolve("@babel/plugin-transform-react-inline-elements")
);
}
// Alias configuration for user-defined modules
const fallback = path.join(__dirname, "../../src/helpers/empty.js"); // returns {}
const alias = {
CustomSections: path.join(rootDir, "app/cms/sections/index.js"),
CustomVizzes: path.join(rootDir, "app/cms/vizzes/index.js")
};
Object.keys(alias).forEach(d => {
if (!fs.existsSync(alias[d])) alias[d] = fallback;
});
alias.$root = rootDir;
alias.$app = path.join(rootDir, "app");
return [
{
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto"
},
{
resolve: {
alias
},
test: /\.js$|\.jsx$/,
loader: "babel-loader",
options: {
compact: process.env.NODE_ENV === "production",
presets: babelPresets,
plugins: babelPlugins
},
include: [
path.join(rootDir, "app"),
path.join(rootDir, "node_modules/@datawheel"),
path.join(rootDir, "../packages"),
path.join(rootDir, "utils"),
path.resolve(rootDir, "canon.js")
]
},
{
test: /\.(png|jpeg|jpg|gif|bmp|tif|tiff|svg|woff|woff2|eot|ttf)$/i,
loader: "url-loader",
options: {
fallback: "file-loader",
limit: 100000
}
},
{
test: /\.(yaml|yml)$/,
loader: "yml-loader"
},
{
test: /\.(scss|sass|css)$/,
// exclude: props.extract ? undefined : [path.join(rootDir, "node_modules/@datawheel")],
use: !props.extract
? ["iso-morphic-style-loader"].concat(cssLoaders)
: [MiniCssExtractPlugin.loader].concat(cssLoaders)
}
];
}