feat: centralized build

This commit is contained in:
cha0s 2021-03-20 06:32:40 -05:00
parent dfbe25624e
commit 89ccd8148b
13 changed files with 5146 additions and 0 deletions

7
packages/build/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
**/*.js
**/*.map
!/.*
!/.neutrinorc.js
!/webpack.config.js
!src/**/*.js
!/test/**/*.js

View File

@ -0,0 +1,39 @@
const {chmod} = require('fs');
const {join} = require('path');
const banner = require('@neutrinojs/banner');
const copy = require('@neutrinojs/copy');
module.exports = require('./src/build/.neutrinorc');
module.exports.use.push(banner({
banner: '#!/usr/bin/env node',
raw: true,
pluginId: 'shebang',
}))
module.exports.use.push(({config}) => {
config
.plugin('executable')
.use(class Executable {
apply(compiler) {
compiler.hooks.afterEmit.tapAsync(
'Executable',
(compilation, callback) => {
chmod(join(__dirname, 'build.js'), 0o755, callback);
},
)
}
});
});
module.exports.use.push(
copy({
patterns: [{
from: 'src/build',
to: 'build',
}],
}),
);

View File

@ -0,0 +1,41 @@
{
"name": "@latus/build",
"version": "1.0.0",
"main": "index.js",
"author": "cha0s",
"license": "MIT",
"bin": {
"latus-build": "./build.js"
},
"scripts": {
"build": "NODE_PATH=./node_modules webpack --config ./webpack.config.js --mode production",
"clean": "rm -rf yarn.lock node_modules/* $(node -e \"process.stdout.write(require('./package.json').files.filter((file) => {const parts = file.split('/'); return 1 === parts.length || 'test' !== parts[0];}).join(' '));\")",
"forcepub": "npm unpublish --force $(node -e 'const {name, version} = require(`./package.json`); process.stdout.write(`${name}@${version}`)') && npm publish",
"lint": "NODE_PATH=./node_modules eslint --config ./.eslintrc.js --format codeframe --ext mjs,js .",
"test": "yarn --silent run build --display none && mocha --colors test.js"
},
"files": [
"build",
"build.js",
"index.js",
"index.js.map",
"test.js",
"test.js.map"
],
"dependencies": {
"@neutrinojs/airbnb": "^9.4.0",
"@neutrinojs/banner": "^9.4.0",
"@neutrinojs/copy": "^9.4.0",
"@neutrinojs/mocha": "^9.4.0",
"chai": "4.2.0",
"commander": "^7.1.0",
"eslint": "^7",
"eslint-import-resolver-webpack": "0.13.0",
"mocha": "^8",
"neutrino": "^9.4.0",
"rimraf": "^3.0.2",
"source-map-support": "0.5.19",
"webpack": "^4",
"webpack-cli": "^3"
}
}

181
packages/build/src/build.js Executable file
View File

@ -0,0 +1,181 @@
/* eslint-disable */
import {spawn} from 'child_process';
import {statSync} from 'fs';
import {join, normalize} from 'path';
import {Command} from 'commander';
import rimraf from 'rimraf';
const program = new Command();
const cwd = normalize(process.cwd());
const localConfig = (filename) => {
let configFile = join(__dirname, 'build', filename);
try {
const localConfig = join(cwd, filename);
statSync(localConfig);
configFile = localConfig;
}
catch (error) {}
return configFile;
}
const build = async (args = []) => {
const {production} = program.opts();
const configFile = localConfig('webpack.config.js');
const child = spawn(
'webpack',
[
'--config',
configFile,
'--mode',
production ? 'production' : 'development',
]
.concat(args),
{
env: {
NODE_PATH: './node_modules',
...process.env,
},
stdio: 'inherit',
},
);
return new Promise((resolve, reject) => {
child.on('error', reject);
child.on('exit', (code) => {
child.off('error', reject);
resolve(code);
});
});
};
program
.command('build', {isDefault: true})
.description('build package')
.action(() => build());
const clean = () => {
rimraf.sync(join(cwd, 'node_modules', '*'));
rimraf.sync(join(cwd, 'yarn.lock'));
const {files} = __non_webpack_require__(join(cwd, 'package.json'));
rimraf.sync(
files
.map((filename) => join(cwd, filename))
.join(' '),
);
};
program
.command('clean')
.description('remove node_modules/*, yarn.lock, and build artifacts')
.action(clean);
const unpublish = async () => {
const {name, version} = __non_webpack_require__(join(cwd, 'package.json'));
const child = spawn(
'npm',
[
'unpublish',
'--force',
`${name}@${version}`,
],
{
stdio: 'inherit',
},
);
return new Promise((resolve, reject) => {
child.on('error', reject);
child.on('exit', (code) => {
child.off('error', reject);
resolve(code);
});
});
};
const publish = async () => {
const child = spawn(
'npm',
[
'publish',
],
{
stdio: 'inherit',
},
);
return new Promise((resolve, reject) => {
child.on('error', reject);
child.on('exit', (code) => {
child.off('error', reject);
resolve(code);
});
});
};
program
.command('forcepublish')
.alias('fp')
.description('force publish to npm')
.action(async () => {
await unpublish();
await publish();
});
const lint = () => {
const {production} = program.opts();
const configFile = localConfig('.eslintrc.js');
spawn(
'eslint',
[
'--config',
configFile,
'--format',
'codeframe',
'--ext',
'mjs,js',
'.',
],
{
env: {
NODE_PATH: './node_modules',
...process.env,
},
stdio: 'inherit',
},
);
};
program
.command('lint')
.description('run linter')
.action(lint);
const test = async () => {
await build(['--display', 'none']);
const {production} = program.opts();
const configFile = localConfig('.eslintrc.js');
spawn(
'mocha',
[
'--colors',
'test.js',
],
{
env: {
NODE_PATH: './node_modules',
...process.env,
},
stdio: 'inherit',
},
);
};
program
.command('test')
.description('build and run tests')
.action(test);
program
.option('-d, --no-production', 'dev build');
program.parse(process.argv);

View File

@ -0,0 +1,23 @@
const config = {
globals: {
__non_webpack_require__: true,
process: true,
window: true,
},
ignorePatterns: [
'/*',
'!/src',
],
rules: {
'babel/object-curly-spacing': 'off',
'brace-style': ['error', 'stroustrup'],
'no-bitwise': ['error', {int32Hint: true}],
'no-plusplus': 'off',
'no-shadow': 'off',
'no-underscore-dangle': 'off',
'padded-blocks': ['error', {classes: 'always'}],
yoda: 'off',
},
};
module.exports = config;

View File

@ -0,0 +1,3 @@
const neutrino = require('neutrino');
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).eslintrc();

View File

@ -0,0 +1,108 @@
const {basename, dirname, extname, join} = require('path');
const airbnb = require('@neutrinojs/airbnb');
const glob = require('glob');
const mocha = require('@neutrinojs/mocha');
const react = require('@neutrinojs/react');
const nodeExternals = require('webpack-node-externals');
module.exports = {
options: {},
use: [
airbnb({
eslint: {
cache: false,
baseConfig: require(`${__dirname}/.eslint.defaults`),
},
}),
(neutrino) => {
const {files = [], name} = neutrino.options.packageJson;
files
.filter((file) => {
const {source} = neutrino.options;
try {
require.resolve(`${source}/${file}`);
return true;
}
catch (error) {
const ext = extname(file);
try {
require.resolve(`${source}/${dirname(file)}/${basename(file, ext)}/index${ext}`);
return true;
}
catch (error) {
return false;
}
}
})
.forEach((file) => {
const isIndex = 'index.js' === file;
const trimmed = join(dirname(file), basename(file, extname(file)));
neutrino.options.mains[trimmed] = {entry: isIndex ? file : `./src/${trimmed}`};
});
const testPaths = glob.sync('./test/*.js');
if (testPaths.length > 0) {
const testEntry = neutrino.config.entry('test').clear();
testPaths.forEach((path) => testEntry.add(path));
}
const cssPaths = glob.sync('./src/**/*.{css,scss}');
if (cssPaths.length > 0) {
const cssEntry = neutrino.config.entry('index.css').clear();
cssPaths.forEach((path) => cssEntry.add(path));
}
neutrino.options.output = '.';
react({
clean: false,
hot: false,
style: {
extract: {
enabled: false,
},
test: /\.(css|sass|scss)$/,
modulesTest: /\.module\.(css|sass|scss)$/,
loaders: [
{
loader: 'postcss-loader',
useId: 'postcss',
options: {
config: {
path: process.cwd(),
},
},
},
{
loader: 'sass-loader',
useId: 'sass',
},
],
},
})(neutrino);
Object.keys(neutrino.options.mains).forEach((main) => {
neutrino.config.plugins.delete(`html-${main}`);
});
neutrino.config
.devtool('source-map')
.target('node')
.optimization
.splitChunks(false)
.runtimeChunk(false)
.end()
.output
.filename('[name].js')
.library(name)
.libraryTarget('umd')
.umdNamedDefine(true)
.end()
.node
.set('__dirname', false)
.set('__filename', false);
const options = neutrino.config.module
.rule('compile')
.use('babel')
.get('options');
options.presets[0][1].targets = {esmodules: true};
neutrino.config.externals(nodeExternals({importType: 'umd'}));
},
mocha(),
],
};

View File

@ -0,0 +1,6 @@
/* eslint-disable global-require */
module.exports = {
plugins: [
require('autoprefixer'),
],
};

View File

@ -0,0 +1,3 @@
const neutrino = require('neutrino');
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();

View File

View File

@ -0,0 +1,5 @@
import {expect} from 'chai';
it('exists', () => {
expect(true).to.be.true;
});

View File

@ -0,0 +1,3 @@
const neutrino = require('neutrino');
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();

4727
packages/build/yarn.lock Normal file

File diff suppressed because it is too large Load Diff