Skip to content

Instantly share code, notes, and snippets.

@ASafaeirad
Created January 30, 2020 06:48
Show Gist options
  • Select an option

  • Save ASafaeirad/b341edd4e2d5e7ccb53f386685397339 to your computer and use it in GitHub Desktop.

Select an option

Save ASafaeirad/b341edd4e2d5e7ccb53f386685397339 to your computer and use it in GitHub Desktop.
const through = require('through2');
const { join, resolve, dirname, sep } = require('path');
const { readFileSync } = require('fs');
const merge = require('merge-deep');
const plumber = require('gulp-plumber');
const { chalks } = require('@frontendmonster/dev-utils');
const ts = require('gulp-typescript');
const gulp = require('gulp');
const filter = require('gulp-filter');
const changed = require('gulp-changed');
const sourcemaps = require('gulp-sourcemaps');
const babel = require('gulp-babel');
const srcToDist = src => src.replace(/src\//, 'dist/');
const tsToJs = src => src.replace(/.ts$/, '.js');
const jsxToJs = src => src.replace(/.jsx$/, '.js');
const toArray = x => (Array.isArray(x) ? x : [x]);
const getPackageInfo = (relative, { exts, title }) => ({
title: title || relative.split(sep).slice(-1)[0],
base: join(__dirname, '..', relative),
globe: toArray(exts).map(ext => `./${relative}/src/**/*.${ext}`),
});
const resolveBabelConfig = configPath => {
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
if (config.extends == null) {
return config;
}
const extendsConfig = JSON.parse(readFileSync(join(dirname(configPath), config.extends), 'utf-8'));
Reflect.deleteProperty(config, 'extends');
const extendedConfig = merge(extendsConfig, config);
return extendedConfig;
};
const noop = () => {
/* Noop */
};
const defaultLogger = {
// eslint-disable-next-line no-console
error: console.error.bind(console),
success: noop,
log: noop,
// eslint-disable-next-line no-console
warn: console.warn.bind(console),
};
const createLogger = logger => ({
log(title) {
return through.obj((file, enc, callback) => {
logger.success(`[${title}] > Compiling '${chalks.processing(file.relative)}'...`);
callback(undefined, file);
});
},
error() {
return plumber({
errorHandler(err) {
logger.error(err.stack);
},
});
},
});
const rename = renamer =>
through.obj((file, enc, callback) => {
file.path = renamer(file);
callback(undefined, file);
});
const buildTS = (relativePath, { logger = defaultLogger, packageName } = {}) => () => {
const streamLogger = createLogger(logger);
const { globe, base, title } = getPackageInfo(relativePath, { title: packageName, exts: 'ts' });
const tsConfig = join(base, 'tsconfig.json');
const typescript = ts.createProject(tsConfig, { outDir: './' });
return gulp
.src(globe, { base })
.pipe(filter(['**', '!**/*.test.ts', '!**/*.d.ts']))
.pipe(streamLogger.error())
.pipe(changed(base, { transformPath: src => tsToJs(srcToDist(src)) }))
.pipe(streamLogger.log(title))
.pipe(sourcemaps.init())
.pipe(typescript())
.pipe(rename(file => resolve(file.base, srcToDist(file.relative))))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(base));
};
const buildBabel = (relativePath, { logger = defaultLogger, packageName } = {}) => () => {
const { globe, base, title } = getPackageInfo(relativePath, { title: packageName, exts: ['js', 'jsx'] });
const babelConfig = resolveBabelConfig(join(base, '.babelrc'));
const streamLogger = createLogger(logger);
return gulp
.src(globe, { base })
.pipe(filter(['**', '!**/*.test.js']))
.pipe(streamLogger.error())
.pipe(changed(base, { transformPath: src => jsxToJs(srcToDist(src)) }))
.pipe(streamLogger.log(title))
.pipe(sourcemaps.init())
.pipe(babel(babelConfig))
.pipe(rename(file => resolve(file.base, srcToDist(file.relative))))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(base));
};
const copyFiles = (relativePath, exts, { logger = defaultLogger, packageName } = {}) => () => {
const { globe, base, title } = getPackageInfo(relativePath, { title: packageName, exts });
const streamLogger = createLogger(logger);
return gulp
.src(globe, { base })
.pipe(changed(base, { transformPath: src => srcToDist(src) }))
.pipe(streamLogger.log(title))
.pipe(rename(file => resolve(file.base, srcToDist(file.relative))))
.pipe(gulp.dest(base));
};
module.exports = {
resolveBabelConfig,
copyFiles,
buildBabel,
buildTS,
};
/* eslint-disable no-console */
const path = require('path');
const { env, Signale } = require('@frontendmonster/dev-utils');
const gulp = require('gulp');
const WebpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');
const { generate, createContext } = require('@graphql-codegen/cli');
const { buildBabel, resolveBabelConfig } = require('./scripts/gulp.utils');
const logger = env.isDev ? Signale('gulp') : undefined;
const BABEL_LOADER_RULE_INDEX = 0;
const packages = {
web: 'packages/web',
ui: 'packages/ui',
};
process.env.WEB_DIR = path.resolve(packages.web);
const resolveWeb = (route = '') => path.resolve(process.env.WEB_DIR, route);
const codegen = done => {
createContext({ config: resolveWeb('codegen.yml') })
.then(context => {
context.updateConfig({
cwd: resolveWeb(),
generates: Object.entries(context.config.generates).reduce(
(acc, [key, val]) => ({ ...acc, [resolveWeb(key)]: val }),
{},
),
});
return context;
})
.then(context => generate(context))
.then(() => done())
.catch(e => {
logger.error(e);
done();
});
};
const getWebpackConfig = () => {
const config = require(resolveWeb('webpack.config.js'));
config.entry = [resolveWeb('src')];
const babelConfig = resolveBabelConfig(resolveWeb('.babelrc'));
config.module.rules[BABEL_LOADER_RULE_INDEX] = {
exclude: /node_modules/,
test: /\.tsx?$/i,
use: {
loader: 'babel-loader',
options: {
...babelConfig,
cacheDirectory: env.isDev,
compact: false,
},
},
};
return config;
};
const startWeb = () => {
const { devServer, ...config } = getWebpackConfig();
WebpackDevServer.addDevServerEntrypoints(config, devServer);
const bundler = webpack(config);
const server = new WebpackDevServer(bundler, devServer);
server.listen(devServer.port, devServer.host, err => {
if (err) {
throw new Error('[WDS]', err);
}
});
};
function buildWeb(done) {
const config = getWebpackConfig({ dev: false });
const compiler = webpack(config);
compiler.run((err, stats) => {
if (err) {
console.log(err);
}
// eslint-disable-next-line no-console
console.log(stats.toString());
done();
});
}
gulp.task('build:ui', buildBabel(packages.ui, { logger }));
gulp.task('codegen', codegen);
gulp.task('build:web:deps', gulp.parallel('build:ui', 'codegen'));
const watchUI = () => gulp.watch(['packages/ui/src/'], gulp.task('build:ui'));
const watchCodegen = () => gulp.watch(['packages/web/src/graphql/'], gulp.task('codegen'));
gulp.task('build:web:core', buildWeb);
gulp.task('build:web', gulp.series('build:web:deps', 'build:web:core'));
gulp.task('start:web', startWeb);
gulp.task('dev:web', gulp.series('build:web:deps', gulp.parallel('start:web', watchUI, watchCodegen)));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment