forked from thednp/bootstrap.native
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build-v4.js
167 lines (159 loc) · 4.99 KB
/
build-v4.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env node
// Native Javascript for Bootstrap 4 | Build Script
// Build script to bundle the js files in lib/v4
// Usage: npm run build-v4
// Run node build-v4.js --help for usage instructions
// by https://github.com/RyanZim
var fs = require('fs');
var uglify = require('uglify-js');
var pack = require('./package.json');
var version = 'v' + pack.version;
var license = pack.license + '-License';
var libPath = __dirname + '/lib';
// Parse arguments:
var argv = require('yargs')
.usage('node build.js [--minify] [--ignore=<modules>...|--only=<modules>...]')
.options({
minify: {
alias: 'm',
type: 'boolean',
default: false,
describe: 'Minify output'
},
ignore: {
alias: 'i',
type: 'array',
describe: 'Omit the given module(s) from the bundle'
},
only: {
type: 'array',
describe: 'Only include the given module(s) in the bundle'
}
})
.coerce(['ignore', 'only'], getModuleNames)
.help()
.epilog(`Running without --ignore or --only will compile all the modules.
Writes to stdout`)
.argv;
// Arguments Sanity Check:
if (argv.only && argv.ignore) {
error('Error: You cannot specify both --only and --ignore.');
}
// Get a list of all modules:
var allModules = fs.readdirSync(`${libPath}/V4`).filter(item => /-native\.js$/.test(item));
// Get a list of modules to include:
var modules = [];
if (argv.only) { // If --only, use that for modules
modules = argv.only.filter(function (item) {
// Validate module names:
var valid = getModuleNames(allModules).some(name => name === item);
if (!valid) {
console.warn(`Warning: ${item} is not a valid module name, continuing`);
}
return valid;
});
} else if (argv.ignore) { // If --ignore, filter allModules
// Filter allModules:
modules = getModuleNames(allModules).filter(function (item) {
// If not in ignore list, return true:
return argv.ignore.every(ignoreItem => ignoreItem !== item);
});
} else { // If neither --ignore or --only, use allModules
modules = getModuleNames(allModules);
}
// If modules is an empty array, abort
// This could happen if you passed non-module values to --only
if (modules.length === 0) {
error(`Error: No valid module names, aborting`);
}
// Use console.warn to avoid writing to stdout
console.warn(`Building Native JavaScript for Bootstrap 4 ${version} ..`);
if (argv.minify) {
console.warn('Minified Build');
} else {
console.warn('Unminified Build');
}
console.warn(`Included modules:
${modules.join('\n ')}`);
// Load modules:
// Use Promises to avoid race conditions
var promises = [];
modules.forEach(function (name, i) {
promises[i] = new Promise(function (resolve, reject) {
fs.readFile(`${libPath}/V4/${name.toLowerCase()}-native.js`, 'utf8', function (err, contents) {
if (err) reject(err);
resolve(contents);
});
});
});
// When all modules are loaded, make bundle:
Promise.all(promises)
.then(function (modules) {
var header = '// Native Javascript for Bootstrap 4 ' + version + ' | © dnp_theme | ' + license + '\n';
var bundle = wrap(modules.join(''));
if (argv.minify) {
bundle = uglify.minify(bundle, {fromString: true}).code;
}
var output = header + bundle + '\n';
process.stdout.on('error', function (err) {
throw err; // Will be caught below
});
process.stdout.write(output, 'utf8');
})
.catch(error);
function wrap(main) {
var utils = fs.readFileSync(`${libPath}/V4/utils.js`, 'utf8').split('\n').join('\n '); // Indentation
main = main.split('\n').join('\n '); // Indentation
// Initialize arrays:
// Arrays will be used in the template literal below
var rootAttachments = [];
var returns = [];
// Populate arrays:
modules.forEach(function (name) {
rootAttachments.push(`root.${name} = bsn.${name};`);
returns.push(`${name}: ${name}`);
});
// Custom UMD Template:
return `(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD support:
define([], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like:
module.exports = factory();
} else {
// Browser globals (root is window)
var bsn = factory();
${rootAttachments.join('\n ')/* add indentation */}
}
}(this, function () {
${utils}
${main}
return {
${returns.join(',\n ')/* add indentation and comma */}
};
}));`;
// End of Template
}
// Helper Functions:
function getModuleNames(arr) { // Normalizes an array of module names or filenames
var regex = /([\w]+)(-native\.js)?/;
var names = [];
arr.forEach(function (str) {
var name = ucfirst(regex.exec(str)[1]);
// Special Casing for ScrollSpy
if (name === 'Scrollspy') {
name = 'ScrollSpy';
}
names.push(name);
});
return names;
}
function ucfirst(str) {
var cap = str.charAt(0).toUpperCase();
return cap + str.substr(1);
}
function error(err) {
console.error(err);
process.exit(1);
}