@tmbr/bundler 0.1.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/cli.js +115 -116
  2. package/error.js +104 -0
  3. package/package.json +8 -11
package/cli.js CHANGED
@@ -1,135 +1,134 @@
1
1
  #!/usr/bin/env node
2
- const webpack = require('webpack');
2
+ const esbuild = require('esbuild');
3
3
  const path = require('path');
4
- const SourceMapDevToolPlugin = require('webpack').SourceMapDevToolPlugin;
5
- const MiniCssExtractPlugin = require('mini-css-extract-plugin');
6
- const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
4
+ const exec = require('child_process').execSync;
5
+ const styles = require('esbuild-sass-plugin').sassPlugin;
6
+ const qrcode = require('qrcode-terminal');
7
+ const chalk = require('chalk');
8
+ const bs = require('browser-sync').create();
9
+ const renderError = require('./error');
7
10
 
8
11
  const cwd = process.cwd();
9
- const command = process.argv[2] || 'build';
10
12
  const package = require(`${cwd}/package.json`);
13
+ const command = process.argv[2];
14
+ let error;
11
15
 
12
- const config = {
13
- entry: {
14
- admin: path.resolve(cwd, 'src/admin'),
15
- main: path.resolve(cwd, 'src'),
16
- },
17
- output: {
18
- path: path.resolve(cwd, 'build'),
19
- filename: '[name].js',
16
+ if (!['build', 'watch'].includes(command)) {
17
+ console.log(`Invalid command: ${chalk.red(command)}\n`);
18
+ process.exit();
19
+ }
20
+
21
+ exec(`rm -rf ${cwd}/build/*`);
22
+
23
+ const assets = (options = {}) => ({
24
+ name: 'assets',
25
+ setup(build) {
26
+ build.onResolve({filter: /..\/(fonts|images)\//}, args => ({
27
+ path: args.path,
28
+ external: true
29
+ }))
20
30
  },
21
- resolve: {
22
- alias: {'@': path.resolve(cwd, 'src')}
31
+ });
32
+
33
+ const errors = (options = {}) => ({
34
+ name: 'errors',
35
+ setup(build) {
36
+ build.onEnd(result => {
37
+ error = result.errors[0];
38
+ error && bs.reload();
39
+ });
23
40
  },
24
- devtool: false,
25
- module: {
26
- rules: [{
27
- test: /\.js$/,
28
- exclude: /node_modules/,
29
- use: {
30
- loader: 'babel-loader',
31
- options: {presets: [['@babel/preset-env', {targets: '> 0.5%, not IE 11, not dead'}]]}
32
- }
33
- }, {
34
- test: /\.(css|scss)$/,
35
- use: [
36
- {loader: MiniCssExtractPlugin.loader, options: {publicPath: ''}},
37
- {loader: 'css-loader'},
38
- {loader: 'sass-loader'},
39
- ]
40
- }, {
41
- test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|json|mp3|mp4|ico)$/,
42
- type: 'asset/resource',
43
- generator: {emit: false, filename: '../[path][name][ext]?[hash]'}
44
- }]
41
+ });
42
+
43
+ function entryPoints(suffix = '') {
44
+
45
+ if (!suffix.startsWith('.')) {
46
+ suffix = `.${suffix}`;
45
47
  }
48
+
49
+ const entries = Object.entries({
50
+ admin: path.resolve(cwd, './src/admin'),
51
+ main: path.resolve(cwd, './src'),
52
+ });
53
+
54
+ return entries.reduce((result, [name, path]) => {
55
+ result[`${name}${suffix}`] = path;
56
+ return result;
57
+ }, {});
58
+ }
59
+
60
+ const defaults = {
61
+ watch: command === 'watch',
62
+ outdir: path.resolve(cwd, 'build'),
63
+ bundle: true,
64
+ minify: true,
65
+ sourcemap: false,
66
+ logLevel: 'warning',
67
+ legalComments: 'none',
68
+ treeShaking: true,
69
+ target: 'es2019',
70
+ plugins: [
71
+ styles({sourceMap: true}),
72
+ assets(),
73
+ ],
46
74
  };
47
75
 
48
- const watchConfig = Object.assign({}, config, {
49
- name: 'watch',
50
- mode: 'development',
51
- stats: {
52
- all: false,
53
- colors: true,
54
- builtAt: true,
55
- timings: true,
56
- warnings: true,
57
- errors: true,
58
- },
76
+ const watchConfig = Object.assign({}, defaults, {
77
+ entryPoints: entryPoints('dev'),
78
+ minify: false,
79
+ sourcemap: 'inline',
80
+ logLevel: 'silent',
59
81
  plugins: [
60
- new SourceMapDevToolPlugin(),
61
- new MiniCssExtractPlugin({
62
- filename: '[name].css'
63
- }),
64
- new BrowserSyncPlugin({
65
- proxy: `${package.name}.test`,
66
- host: 'localhost',
67
- port: 5000,
68
- open: false,
69
- notify: false,
70
- files: ['build/main.js', 'images/*', '**/*.php']
71
- })
72
- ]
82
+ ...defaults.plugins,
83
+ errors()
84
+ ],
73
85
  });
74
86
 
75
- const buildConfig = Object.assign({}, config, {
76
- name: 'build',
77
- mode: 'production',
78
- output: {
79
- path: path.resolve(cwd, 'build'),
80
- filename: '[name].min.js',
81
- },
82
- stats: 'none',
83
- plugins: [
84
- new MiniCssExtractPlugin({
85
- filename: '[name].min.css'
86
- })
87
- ]
87
+ const buildConfig = Object.assign({}, defaults, {
88
+ entryPoints: entryPoints('min'),
88
89
  });
89
90
 
90
- function callback(err, stats) {
91
- if (err) {
92
- console.error(err.stack || err);
93
- if (err.details) {
94
- console.error(err.details);
95
- }
96
- return;
97
- }
98
- const info = stats.toJson();
99
- if (stats.hasErrors()) {
100
- console.error(info.errors);
101
- }
102
- if (stats.hasWarnings()) {
103
- console.warn(info.warnings);
104
- }
105
- // Log result...
106
- }
91
+ esbuild.build(watchConfig);
92
+ esbuild.build(buildConfig);
107
93
 
108
- const compiler = webpack([
109
- watchConfig,
110
- buildConfig
111
- ]);
112
-
113
- switch (command) {
114
-
115
- case 'watch':
116
- compiler.watch({
117
- // https://webpack.js.org/configuration/watch/#watchoptions
118
- aggregateTimeout: 300,
119
- poll: undefined
120
- }, callback);
121
- break;
122
-
123
- case 'build':
124
- compiler.run((err, stats) => {
125
- // https://webpack.js.org/api/node/#stats-object
126
- // https://webpack.js.org/configuration/stats/
127
- console.log(stats.toJson());
128
- // callback(err, stats);
129
- compiler.close();
130
- });
131
- break;
94
+ if (command === 'watch') {
95
+
96
+ const watchedBuilds = Object.keys(watchConfig.entryPoints).map(name => (
97
+ `${watchConfig.outdir}/${name}.*`
98
+ ));
99
+
100
+ const files = [
101
+ ...watchedBuilds,
102
+ 'images/*',
103
+ '**/*.php'
104
+ ];
105
+
106
+ const middleware = (proxyRes, req, res) => {
107
+ error && res.end(renderError(error));
108
+ };
109
+
110
+ const options = {
111
+ proxy: {
112
+ target: `${package.name}.test`,
113
+ proxyRes: [middleware]
114
+ },
115
+ host: 'localhost',
116
+ open: false,
117
+ notify: false,
118
+ logLevel: 'silent',
119
+ ui: false,
120
+ files
121
+ };
122
+
123
+ bs.init(options, () => {
124
+
125
+ const host = bs.getOption('proxy').get('target');
126
+ const port = bs.getOption('port');
127
+ const proxying = `${host}:${port}`;
128
+ const external = bs.getOption('urls').get('external');
132
129
 
133
- default:
134
- console.log(`Command "${command}" not found`);
130
+ external && qrcode.generate(external, {small: true}, console.log);
131
+ console.log(`Proxying: ${chalk.green(proxying)}`);
132
+ console.log(`External: ${chalk.cyan(external || 'offline')}`);
133
+ });
135
134
  }
package/error.js ADDED
@@ -0,0 +1,104 @@
1
+ const fs = require('fs');
2
+ const encode = require('html-entities').encode;
3
+
4
+ module.exports = error => {
5
+
6
+ const { file, line, column } = error.location;
7
+
8
+ const lines = fs.readFileSync(file, 'UTF-8').split(/\r?\n/);
9
+ const index = line - 1;
10
+ const space = ' ';
11
+
12
+ const inset = String((lines[index + 2] && line + 2) || (lines[index + 1] && line + 1) || line).split('').length;
13
+ const print = offset => (
14
+ `<span class="c-gray">${String(line + offset).padStart(2 + inset, ' ')} | </span>` + encode(lines[index + offset])
15
+ );
16
+
17
+ const output = [
18
+ (index - 2) >= 0 && print(-2),
19
+ (index - 1) >= 0 && print(-1),
20
+ `<span class="c-red fw-700">&gt;</span><span class="c-gray"> ${line} | </span>${encode(lines[index])}`,
21
+ ` <span class="c-gray">${space.repeat(2 + inset)}| </span>${space.repeat(column ? column - 1 : 0)}<span class="c-red fw-700">^</span>`,
22
+ (index + 1) <= lines.length - 1 && print(1),
23
+ (index + 2) <= lines.length - 1 && print(2),
24
+ ].filter(Boolean).join('\n');
25
+
26
+ return /* html */`
27
+ <!DOCTYPE html>
28
+ <html>
29
+ <head>
30
+
31
+ <meta charset="UTF-8">
32
+ <meta content="width=device-width, initial-scale=1.0" name="viewport">
33
+
34
+ <title>Build Error: ${file}</title>
35
+
36
+ <style>
37
+
38
+ * {
39
+ margin: 0;
40
+ padding: 0;
41
+ box-sizing: border-box;
42
+ }
43
+
44
+ .c-red { color: #ff5555; }
45
+ .c-cyan { color: #88ddff; }
46
+ .c-gray { color: #666666; }
47
+ .fw-700 { font-weight: 700; }
48
+
49
+ ::selection {
50
+ background-color: rgba(95, 126, 151, 0.48);
51
+ }
52
+
53
+ html {
54
+ font: 1rem / 1.5 sans-serif;
55
+ color: #FFF;
56
+ background-color: #151515;
57
+ }
58
+ main {
59
+ max-width: 1280px;
60
+ margin: 3em auto;
61
+ padding: 1rem;
62
+ }
63
+ h1 {
64
+ font-size: 1.5rem;
65
+ line-height: 1.5;
66
+ margin-bottom: 0.25em;
67
+ }
68
+
69
+ .terminal {
70
+ color: #CCC;
71
+ border-radius: 0.25rem;
72
+ }
73
+ .terminal pre {
74
+ font-family: Menlo, Monaco, monospace;
75
+ overflow: scroll;
76
+ }
77
+ .terminal > * {
78
+ padding: 1rem 0;
79
+ }
80
+
81
+ </style>
82
+
83
+ </head>
84
+ <body>
85
+
86
+ <main>
87
+
88
+ <h1>Build Error</h1>
89
+
90
+ <div class="terminal">
91
+
92
+ <pre>
93
+ <span class="c-cyan">${file}</span><span class="c-gray">:</span>${line}<span class="c-gray">:</span>${column}
94
+ <span class="c-red fw-700">${error.text}</span>
95
+
96
+ ${output}
97
+ </pre>
98
+
99
+ </div>
100
+
101
+ </main>
102
+
103
+ </body>
104
+ </html>`};
package/package.json CHANGED
@@ -1,22 +1,19 @@
1
1
  {
2
2
  "name": "@tmbr/bundler",
3
3
  "author": "TMBR (https://wearetmbr.com/)",
4
- "version": "0.1.3",
4
+ "version": "1.1.0",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/TMBR/tmbr-bundler",
7
- "description": "WordPress development toolkit built on webpack and browser-sync",
7
+ "description": "WordPress development toolkit built on esbuild and browser-sync",
8
8
  "bin": {
9
9
  "tmbr-bundler": "cli.js"
10
10
  },
11
11
  "dependencies": {
12
- "@babel/core": "^7.12.17",
13
- "@babel/preset-env": "^7.12.17",
14
- "babel-loader": "^8.2.2",
15
- "browser-sync-webpack-plugin": "^2.3.0",
16
- "css-loader": "^5.0.2",
17
- "mini-css-extract-plugin": "^1.3.8",
18
- "sass": "^1.32.8",
19
- "sass-loader": "^11.0.1",
20
- "webpack": "^5.23.0"
12
+ "browser-sync": "^2.27.5",
13
+ "chalk": "^4.1.2",
14
+ "esbuild": "^0.13.12",
15
+ "esbuild-sass-plugin": "^1.5.2",
16
+ "html-entities": "^2.3.2",
17
+ "qrcode-terminal": "^0.12.0"
21
18
  }
22
19
  }