@videinfra/static-website-builder 1.11.0 → 1.12.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.
- package/CHANGELOG.md +8 -0
- package/lib/generate-gulp-tasks.js +4 -3
- package/lib/get-config.js +157 -157
- package/lib/gulp/dynamic-task.js +8 -0
- package/lib/gulp/resolve-dynamic-task.js +11 -0
- package/lib/run-preprocess.js +1 -1
- package/package.json +4 -1
- package/tasks/javascripts/config.js +13 -2
- package/tasks/javascripts/preprocess-config.js +120 -73
- package/tasks/javascripts/task.js +40 -16
- package/tests/run-preprocess.test.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.12.0] - 2024-02-25
|
|
8
|
+
### Added
|
|
9
|
+
- Support for multiple entry lists which each has its own "shared" chunk file
|
|
10
|
+
|
|
11
|
+
## [1.11.1] - 2024-02-24
|
|
12
|
+
### Fixed
|
|
13
|
+
- Fixed dependencies
|
|
14
|
+
|
|
7
15
|
## [1.11.0] - 2024-02-24
|
|
8
16
|
### Updated
|
|
9
17
|
- Added dynamic entries, webpack will rebuild when entries change
|
|
@@ -3,6 +3,7 @@ const assign = require('lodash/assign');
|
|
|
3
3
|
const filter = require('lodash/filter');
|
|
4
4
|
const { series, parallel } = require('gulp');
|
|
5
5
|
const { DEFAULT_TASKS, BUILD_TASKS } = require('./task-order');
|
|
6
|
+
const resolveDynamicTask = require('./gulp/resolve-dynamic-task');
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -28,16 +29,16 @@ function generateTaskList (taskConfig) {
|
|
|
28
29
|
|
|
29
30
|
// Create individual tasks, which can be run separatelly
|
|
30
31
|
for (let gulpTaskName in gulpTaskList) {
|
|
31
|
-
taskList.separate[`${ taskName }-${ gulpTaskName }`] = gulpTaskList[gulpTaskName];
|
|
32
|
+
taskList.separate[`${ taskName }-${ gulpTaskName }`] = resolveDynamicTask(gulpTaskList[gulpTaskName]);
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
for (let t = 0; t < DEFAULT_TASKS.length; t++) {
|
|
35
36
|
if (DEFAULT_TASKS[t] in gulpTaskList) {
|
|
36
|
-
const gulpTask = gulpTaskList[DEFAULT_TASKS[t]];
|
|
37
|
+
const gulpTask = resolveDynamicTask(gulpTaskList[DEFAULT_TASKS[t]]);
|
|
37
38
|
taskList.default[t].push(gulpTask);
|
|
38
39
|
}
|
|
39
40
|
if (BUILD_TASKS[t] in gulpTaskList) {
|
|
40
|
-
const gulpTask = gulpTaskList[BUILD_TASKS[t]];
|
|
41
|
+
const gulpTask = resolveDynamicTask(gulpTaskList[BUILD_TASKS[t]]);
|
|
41
42
|
taskList.build[t].push(gulpTask);
|
|
42
43
|
}
|
|
43
44
|
}
|
package/lib/get-config.js
CHANGED
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const getPath = require('./get-path');
|
|
4
|
-
const runPreprocess = require('./run-preprocess');
|
|
5
|
-
const merge = require('./merge');
|
|
6
|
-
const logError = require('./log-error');
|
|
7
|
-
|
|
8
|
-
const each = require('lodash/each');
|
|
9
|
-
const omit = require('lodash/omit');
|
|
10
|
-
const isPlainObject = require('lodash/isPlainObject');
|
|
11
|
-
const isArray = require('lodash/isArray');
|
|
12
|
-
const reduce = require('lodash/reduce');
|
|
13
|
-
const get = require('lodash/get');
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Returns builder and project specific task and plugin configurations combined
|
|
18
|
-
* Configuration is preprocessed
|
|
19
|
-
*
|
|
20
|
-
* @returns {object} Task configurations
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
let taskConfig = null;
|
|
24
|
-
|
|
25
|
-
function getConfig (builderConfigFile) {
|
|
26
|
-
if (!taskConfig) {
|
|
27
|
-
// Load all task configs
|
|
28
|
-
taskConfig = itterateConfig(loadConfig(), mergeConfigMode);
|
|
29
|
-
|
|
30
|
-
// 1. First load project specific config.js
|
|
31
|
-
const projectConfigPath = getPath.getProjectPath(builderConfigFile);
|
|
32
|
-
let projectTaskConfig = {};
|
|
33
|
-
let hasProjectConfigFile = true;
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
fs.accessSync(projectConfigPath);
|
|
37
|
-
} catch (err) {
|
|
38
|
-
logError({'plugin': 'static-website-builder', 'message': `Couldn't find configuration file "${ projectConfigPath }"`});
|
|
39
|
-
hasProjectConfigFile = false;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (hasProjectConfigFile) {
|
|
43
|
-
projectTaskConfig = itterateConfig(require(projectConfigPath), mergeConfigMode);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// 2. Marge plugins into the config, each plugin is just a config
|
|
47
|
-
const plugins = (taskConfig.plugins || []).concat(projectTaskConfig.plugins || []);
|
|
48
|
-
if (plugins) {
|
|
49
|
-
taskConfig.plugins = null;
|
|
50
|
-
projectTaskConfig.plugins = null;
|
|
51
|
-
|
|
52
|
-
each(plugins, (plugin) => {
|
|
53
|
-
taskConfig = merge(taskConfig, itterateConfig(plugin, mergeConfigMode));
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 3. Only after plugins has been executed, merge project specific config.js into main config
|
|
58
|
-
if (projectTaskConfig) {
|
|
59
|
-
taskConfig = merge(taskConfig, projectTaskConfig);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 4. Preprocess
|
|
63
|
-
taskConfig = runPreprocess(taskConfig);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return taskConfig;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Returns task sub-config by path
|
|
71
|
-
*
|
|
72
|
-
* @param {...string} path Path to the sub-config
|
|
73
|
-
* @returns {any} Task sub-config
|
|
74
|
-
*/
|
|
75
|
-
function getTaskConfig (...path) {
|
|
76
|
-
return get(getConfig(), path, null);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Itterate over each config property and call function on
|
|
81
|
-
* each object or array
|
|
82
|
-
*
|
|
83
|
-
* @param {*} object
|
|
84
|
-
* @param {*} fn
|
|
85
|
-
* @protected
|
|
86
|
-
*/
|
|
87
|
-
function itterateConfig (config, fn) {
|
|
88
|
-
if (config === false) return false;
|
|
89
|
-
const base = isPlainObject(config) ? {} : [];
|
|
90
|
-
|
|
91
|
-
return reduce(config, (object, value, key) => {
|
|
92
|
-
if (isPlainObject(value)) {
|
|
93
|
-
object[key]= itterateConfig(fn(value), fn);
|
|
94
|
-
} else if (isArray(value)) {
|
|
95
|
-
object[key]= itterateConfig(value, fn);
|
|
96
|
-
} else {
|
|
97
|
-
object[key] = value;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return object;
|
|
101
|
-
}, base);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Merge 'production' or 'development' mode sub-ojbects into an object and remove
|
|
106
|
-
* mode sub-objects
|
|
107
|
-
*
|
|
108
|
-
* @param {object} config Config
|
|
109
|
-
* @returns {object} Config
|
|
110
|
-
* @protected
|
|
111
|
-
*/
|
|
112
|
-
function mergeConfigMode (config) {
|
|
113
|
-
if ('production' in config || 'development' in config) {
|
|
114
|
-
const mode = global.production ? 'production' : 'development';
|
|
115
|
-
const value = merge(config, config[mode]);
|
|
116
|
-
|
|
117
|
-
if (value !== false) {
|
|
118
|
-
return omit(value, ['production', 'development']);
|
|
119
|
-
} else {
|
|
120
|
-
return value;
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
return config;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Load config files
|
|
129
|
-
*
|
|
130
|
-
* @returns {object} Configuration
|
|
131
|
-
* @protected
|
|
132
|
-
*/
|
|
133
|
-
function loadConfig () {
|
|
134
|
-
const taskFolder = path.resolve(__dirname, '../tasks');
|
|
135
|
-
let taskConfig = {};
|
|
136
|
-
|
|
137
|
-
fs.readdirSync(taskFolder).forEach(folderName => {
|
|
138
|
-
// Ignore task folders which start with underscore
|
|
139
|
-
if (folderName[0] !== '_') {
|
|
140
|
-
const configFileName = path.resolve(taskFolder, folderName, 'config.js');
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
fs.accessSync(configFileName);
|
|
144
|
-
} catch (err) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
taskConfig = merge(taskConfig, require(configFileName));
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
return taskConfig;
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
exports.getConfig = getConfig;
|
|
157
|
-
exports.getTaskConfig = getTaskConfig;
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const getPath = require('./get-path');
|
|
4
|
+
const runPreprocess = require('./run-preprocess');
|
|
5
|
+
const merge = require('./merge');
|
|
6
|
+
const logError = require('./log-error');
|
|
7
|
+
|
|
8
|
+
const each = require('lodash/each');
|
|
9
|
+
const omit = require('lodash/omit');
|
|
10
|
+
const isPlainObject = require('lodash/isPlainObject');
|
|
11
|
+
const isArray = require('lodash/isArray');
|
|
12
|
+
const reduce = require('lodash/reduce');
|
|
13
|
+
const get = require('lodash/get');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns builder and project specific task and plugin configurations combined
|
|
18
|
+
* Configuration is preprocessed
|
|
19
|
+
*
|
|
20
|
+
* @returns {object} Task configurations
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
let taskConfig = null;
|
|
24
|
+
|
|
25
|
+
function getConfig (builderConfigFile) {
|
|
26
|
+
if (!taskConfig) {
|
|
27
|
+
// Load all task configs
|
|
28
|
+
taskConfig = itterateConfig(loadConfig(), mergeConfigMode);
|
|
29
|
+
|
|
30
|
+
// 1. First load project specific config.js
|
|
31
|
+
const projectConfigPath = getPath.getProjectPath(builderConfigFile);
|
|
32
|
+
let projectTaskConfig = {};
|
|
33
|
+
let hasProjectConfigFile = true;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
fs.accessSync(projectConfigPath);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
logError({'plugin': 'static-website-builder', 'message': `Couldn't find configuration file "${ projectConfigPath }"`});
|
|
39
|
+
hasProjectConfigFile = false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (hasProjectConfigFile) {
|
|
43
|
+
projectTaskConfig = itterateConfig(require(projectConfigPath), mergeConfigMode);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 2. Marge plugins into the config, each plugin is just a config
|
|
47
|
+
const plugins = (taskConfig.plugins || []).concat(projectTaskConfig.plugins || []);
|
|
48
|
+
if (plugins) {
|
|
49
|
+
taskConfig.plugins = null;
|
|
50
|
+
projectTaskConfig.plugins = null;
|
|
51
|
+
|
|
52
|
+
each(plugins, (plugin) => {
|
|
53
|
+
taskConfig = merge(taskConfig, itterateConfig(plugin, mergeConfigMode));
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 3. Only after plugins has been executed, merge project specific config.js into main config
|
|
58
|
+
if (projectTaskConfig) {
|
|
59
|
+
taskConfig = merge(taskConfig, projectTaskConfig);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 4. Preprocess
|
|
63
|
+
taskConfig = runPreprocess(taskConfig);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return taskConfig;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns task sub-config by path
|
|
71
|
+
*
|
|
72
|
+
* @param {...string} path Path to the sub-config
|
|
73
|
+
* @returns {any} Task sub-config
|
|
74
|
+
*/
|
|
75
|
+
function getTaskConfig (...path) {
|
|
76
|
+
return get(getConfig(), path, null);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Itterate over each config property and call function on
|
|
81
|
+
* each object or array
|
|
82
|
+
*
|
|
83
|
+
* @param {*} object
|
|
84
|
+
* @param {*} fn
|
|
85
|
+
* @protected
|
|
86
|
+
*/
|
|
87
|
+
function itterateConfig (config, fn) {
|
|
88
|
+
if (config === false) return false;
|
|
89
|
+
const base = isPlainObject(config) ? {} : [];
|
|
90
|
+
|
|
91
|
+
return reduce(config, (object, value, key) => {
|
|
92
|
+
if (isPlainObject(value)) {
|
|
93
|
+
object[key]= itterateConfig(fn(value), fn);
|
|
94
|
+
} else if (isArray(value)) {
|
|
95
|
+
object[key]= itterateConfig(value, fn);
|
|
96
|
+
} else {
|
|
97
|
+
object[key] = value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return object;
|
|
101
|
+
}, base);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Merge 'production' or 'development' mode sub-ojbects into an object and remove
|
|
106
|
+
* mode sub-objects
|
|
107
|
+
*
|
|
108
|
+
* @param {object} config Config
|
|
109
|
+
* @returns {object} Config
|
|
110
|
+
* @protected
|
|
111
|
+
*/
|
|
112
|
+
function mergeConfigMode (config) {
|
|
113
|
+
if ('production' in config || 'development' in config) {
|
|
114
|
+
const mode = global.production ? 'production' : 'development';
|
|
115
|
+
const value = merge(config, config[mode]);
|
|
116
|
+
|
|
117
|
+
if (value !== false) {
|
|
118
|
+
return omit(value, ['production', 'development']);
|
|
119
|
+
} else {
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
return config;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Load config files
|
|
129
|
+
*
|
|
130
|
+
* @returns {object} Configuration
|
|
131
|
+
* @protected
|
|
132
|
+
*/
|
|
133
|
+
function loadConfig () {
|
|
134
|
+
const taskFolder = path.resolve(__dirname, '../tasks');
|
|
135
|
+
let taskConfig = {};
|
|
136
|
+
|
|
137
|
+
fs.readdirSync(taskFolder).forEach(folderName => {
|
|
138
|
+
// Ignore task folders which start with underscore
|
|
139
|
+
if (folderName[0] !== '_') {
|
|
140
|
+
const configFileName = path.resolve(taskFolder, folderName, 'config.js');
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
fs.accessSync(configFileName);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
taskConfig = merge(taskConfig, require(configFileName));
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return taskConfig;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
exports.getConfig = getConfig;
|
|
157
|
+
exports.getTaskConfig = getTaskConfig;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Similar to parallel() and serial() but instead of getting tasks immediatelly
|
|
3
|
+
* it's executed after config has been loaded
|
|
4
|
+
*/
|
|
5
|
+
module.exports = function resolveDynamicTask (fn) {
|
|
6
|
+
if (fn.dynamicTasks) {
|
|
7
|
+
return fn();
|
|
8
|
+
} else {
|
|
9
|
+
return fn;
|
|
10
|
+
}
|
|
11
|
+
}
|
package/lib/run-preprocess.js
CHANGED
|
@@ -19,7 +19,7 @@ module.exports = function runPreprocess (taskConfig) {
|
|
|
19
19
|
if (newTaskConfig === false) {
|
|
20
20
|
taskConfig[taskName] = false;
|
|
21
21
|
break;
|
|
22
|
-
} else if (newTaskConfig && isPlainObject(newTaskConfig)) {
|
|
22
|
+
} else if (newTaskConfig && (isPlainObject(newTaskConfig) || Array.isArray(newTaskConfig))) {
|
|
23
23
|
// Safeguard against empty values
|
|
24
24
|
taskConfig[taskName] = newTaskConfig;
|
|
25
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@videinfra/static-website-builder",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"description": "Customizable static site project builder",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -50,11 +50,14 @@
|
|
|
50
50
|
"gulp-sourcemaps": "^3.0.0",
|
|
51
51
|
"gulp-svgmin": "^4.1.0",
|
|
52
52
|
"gulp-svgstore": "^9.0.0",
|
|
53
|
+
"lodash.clone": "^4.3.2",
|
|
54
|
+
"lodash.some": "^4.2.2",
|
|
53
55
|
"map-stream": "^0.1.0",
|
|
54
56
|
"minimist": "^1.2.8",
|
|
55
57
|
"nano-memoize": "1.3.0",
|
|
56
58
|
"node-sass": "^7.0.3",
|
|
57
59
|
"sass": "^1.65.1",
|
|
60
|
+
"through": "^2.3.8",
|
|
58
61
|
"twig": "^1.10.5",
|
|
59
62
|
"webpack": "^4.46.0",
|
|
60
63
|
"webpack-watch-files-plugin": "^1.2.1"
|
|
@@ -7,7 +7,15 @@ exports.javascripts = {
|
|
|
7
7
|
extensions: ['js', 'json'],
|
|
8
8
|
|
|
9
9
|
// Instead of 'entry' we provide filename which list all entries
|
|
10
|
-
|
|
10
|
+
// Can be either an object or array of object to have multiple webpack
|
|
11
|
+
// build, one for each of the entry list files
|
|
12
|
+
entryList: {
|
|
13
|
+
// Path to the entry list file
|
|
14
|
+
name: '_entries.js',
|
|
15
|
+
|
|
16
|
+
// Entry shared chunk name, creates webpack.optimization chunks
|
|
17
|
+
shared: 'shared',
|
|
18
|
+
},
|
|
11
19
|
|
|
12
20
|
// Webpack configuration
|
|
13
21
|
// see https://webpack.js.org/configuration/
|
|
@@ -33,8 +41,11 @@ exports.javascripts = {
|
|
|
33
41
|
],
|
|
34
42
|
},
|
|
35
43
|
|
|
44
|
+
// Default optimization, 'shared' will be overwritten by entryList.shared value
|
|
36
45
|
optimization: {
|
|
37
|
-
runtimeChunk: {
|
|
46
|
+
runtimeChunk: {
|
|
47
|
+
name: 'shared'
|
|
48
|
+
},
|
|
38
49
|
splitChunks: {
|
|
39
50
|
cacheGroups: {
|
|
40
51
|
default: false,
|
|
@@ -2,6 +2,7 @@ const paths = require('../../lib/get-path');
|
|
|
2
2
|
const merge = require('../../lib/merge');
|
|
3
3
|
const get = require('lodash/get');
|
|
4
4
|
const map = require('lodash/map');
|
|
5
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
5
6
|
const webpack = require('webpack');
|
|
6
7
|
const WatchExternalFilesPlugin = require('webpack-watch-files-plugin');
|
|
7
8
|
|
|
@@ -22,32 +23,10 @@ function requireUncached(module) {
|
|
|
22
23
|
* @returns {object} List of entry files
|
|
23
24
|
*/
|
|
24
25
|
function getEntry (config) {
|
|
25
|
-
const entryFile = paths.getSourcePath('javascripts', config.entryList);
|
|
26
|
-
|
|
27
|
-
// console.log(require(entryFile));
|
|
28
|
-
// return () => {
|
|
29
|
-
// return new Promise((resolve) => {
|
|
30
|
-
// resolve(require(entryFile));
|
|
31
|
-
// });
|
|
32
|
-
// };
|
|
33
|
-
|
|
34
|
-
// return () => new Promise((resolve) => {
|
|
35
|
-
// resolve(['./demo', './demo2'])
|
|
36
|
-
// });
|
|
26
|
+
const entryFile = paths.getSourcePath('javascripts', config.entryList.name);
|
|
37
27
|
|
|
38
28
|
return function getEntries () {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// console.log(require.cache.);
|
|
42
|
-
// console.log('loading entries:', entryURL);
|
|
43
|
-
// return import(entryURL).then((entries) => {
|
|
44
|
-
// console.log('loaded entries:', entries.default);
|
|
45
|
-
// return entries.default;
|
|
46
|
-
// });
|
|
47
|
-
|
|
48
|
-
const entries = requireUncached(entryFile);
|
|
49
|
-
console.log('entries:', entries);
|
|
50
|
-
return entries;
|
|
29
|
+
return requireUncached(entryFile);
|
|
51
30
|
}
|
|
52
31
|
}
|
|
53
32
|
|
|
@@ -65,56 +44,124 @@ module.exports = function preprocessJavascriptsConfig (config, fullConfig) {
|
|
|
65
44
|
webpackPlugins = webpackPlugins(webpack);
|
|
66
45
|
}
|
|
67
46
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
47
|
+
// User may specify a function, execute it to get object / array
|
|
48
|
+
if (typeof config.entryList === 'function') {
|
|
49
|
+
config.entryList = config.entryList(config);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// User may specify multiple entry list files, convert to array
|
|
53
|
+
if (!Array.isArray(config.entryList)) {
|
|
54
|
+
config.entryList = [config.entryList];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// User may specify only a name of the entry file
|
|
58
|
+
// Set shared chunk name for each of the entry files
|
|
59
|
+
// Each entryList item is { name: '...', shared: '...' }
|
|
60
|
+
config.entryList = config.entryList.map((entry, index) => {
|
|
61
|
+
return {
|
|
62
|
+
name: typeof entry === 'string' ? entry : entry.name,
|
|
63
|
+
shared: typeof entry !== 'string' && entry && entry.shared ? entry.shared : (index === 0 ? 'shared' : ''),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return config.entryList.map((entryList) => {
|
|
68
|
+
const entryConfig = Object.assign({}, config);
|
|
69
|
+
entryConfig.webpack = Object.assign({}, entryConfig.webpack);
|
|
70
|
+
|
|
71
|
+
// One entry file per config
|
|
72
|
+
entryConfig.entryList = entryList;
|
|
73
|
+
|
|
74
|
+
const buildConfig = merge(entryConfig, {
|
|
75
|
+
webpack: {
|
|
76
|
+
mode: global.production ? 'production' : 'development',
|
|
77
|
+
|
|
78
|
+
// Input files
|
|
79
|
+
context: paths.getSourcePath('javascripts'),
|
|
80
|
+
entry: getEntry(entryConfig),
|
|
81
|
+
|
|
82
|
+
// Output folder
|
|
83
|
+
output: merge({
|
|
84
|
+
path: paths.getDestPath('javascripts'),
|
|
85
|
+
publicPath: paths.getPublicPath('javascripts'),
|
|
86
|
+
}, get(entryConfig, ['webpack', 'output'], null)),
|
|
87
|
+
|
|
88
|
+
// Plugins, add ENV variables
|
|
89
|
+
plugins: [
|
|
90
|
+
new webpack.DefinePlugin({
|
|
91
|
+
'process.env.NODE_ENV': JSON.stringify(global.production ? 'production' : 'development'),
|
|
92
|
+
}),
|
|
93
|
+
new WatchExternalFilesPlugin.default({
|
|
94
|
+
verbose: false,
|
|
95
|
+
files: [
|
|
96
|
+
paths.getSourcePath('javascripts', entryList.name),
|
|
97
|
+
],
|
|
98
|
+
}),
|
|
99
|
+
].concat(webpackPlugins),
|
|
100
|
+
|
|
101
|
+
// Imports
|
|
102
|
+
resolve: merge({
|
|
103
|
+
// File extensions
|
|
104
|
+
extensions: map(entryConfig.extensions, (extension) => `.${ extension }`),
|
|
105
|
+
|
|
106
|
+
// Import folders
|
|
107
|
+
modules: [
|
|
108
|
+
// Allow imports from node_modules
|
|
109
|
+
paths.getProjectPath('node_modules'),
|
|
110
|
+
|
|
111
|
+
// Allow imports from source folder
|
|
112
|
+
paths.getSourcePath('javascripts'),
|
|
91
113
|
],
|
|
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
|
-
|
|
114
|
+
}, get(entryConfig, ['webpack', 'resolve'], null)),
|
|
115
|
+
|
|
116
|
+
// Loader imports
|
|
117
|
+
resolveLoader: {
|
|
118
|
+
modules: [
|
|
119
|
+
// Allow imports from node_modules
|
|
120
|
+
paths.getBuilderPath('node_modules'),
|
|
121
|
+
paths.getProjectPath('node_modules'),
|
|
122
|
+
]
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Add webpack.optimization.runtimeChunk and webpack.optimization.splitChunks,
|
|
128
|
+
// if entryConfig.shared doesn't exist, then remove them
|
|
129
|
+
if (entryList.shared && entryList.shared !== 'shared') {
|
|
130
|
+
const optimization = buildConfig.webpack.optimization = cloneDeep(buildConfig.webpack.optimization || {});
|
|
131
|
+
|
|
132
|
+
if (get(optimization, ['runtimeChunk', 'name'], null) === 'shared') {
|
|
133
|
+
// Change shared runtimeChunk name
|
|
134
|
+
optimization.runtimeChunk.name = entryList.shared;
|
|
135
|
+
} else if (!optimization.runtimeChunk) {
|
|
136
|
+
// Add shared runtimeChunk
|
|
137
|
+
optimization.runtimeChunk = {
|
|
138
|
+
name: entryList.shared,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if ('shared' in get(optimization, ['splitChunks', 'cacheGroups'], {})) {
|
|
143
|
+
// Rename split chunks "shared" chunk
|
|
144
|
+
const cacheGroups = optimization.splitChunks.cacheGroups.shared;
|
|
145
|
+
delete(optimization.splitChunks.cacheGroups.shared);
|
|
146
|
+
optimization.splitChunks.cacheGroups[entryList.shared] = cacheGroups;
|
|
147
|
+
cacheGroups.name = entryList.shared;
|
|
148
|
+
} else if (!optimization.splitChunks) {
|
|
149
|
+
// Add splitChunks
|
|
150
|
+
optimization.splitChunks = optimization.splitChunks || {};
|
|
151
|
+
optimization.splitChunks.cacheGroups = optimization.splitChunks.cacheGroups || {};
|
|
152
|
+
optimization.splitChunks.cacheGroups[entryList.shared] = {
|
|
153
|
+
name: entryList.shared,
|
|
154
|
+
chunks: 'all',
|
|
155
|
+
minChunks: 3,
|
|
156
|
+
enforce: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
} else if (!entryList.shared) {
|
|
160
|
+
// Remove optimization
|
|
161
|
+
delete(buildConfig.webpack.optimization);
|
|
118
162
|
}
|
|
163
|
+
|
|
164
|
+
return buildConfig;
|
|
119
165
|
});
|
|
166
|
+
|
|
120
167
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const gulp = require('gulp');
|
|
2
|
+
const { parallel } = require('gulp');
|
|
2
3
|
const webpack = require('webpack');
|
|
3
4
|
const gulpWebpack = require('../../vendor/webpack-stream/index.js');
|
|
4
5
|
const memoize = require('nano-memoize');
|
|
@@ -11,12 +12,12 @@ const getConfig = require('./../../lib/get-config');
|
|
|
11
12
|
const taskStart = require('../../lib/gulp/task-start');
|
|
12
13
|
const taskEnd = require('../../lib/gulp/task-end');
|
|
13
14
|
const taskBeforeDest = require('../../lib/gulp/task-before-dest');
|
|
14
|
-
|
|
15
|
+
const dynamicTask = require('../../lib/gulp/dynamic-task');
|
|
15
16
|
|
|
16
17
|
const getGlobPaths = memoize(function () {
|
|
17
18
|
const sourcePaths = getPaths.getSourcePaths('javascripts');
|
|
18
|
-
const extensions = getConfig.getTaskConfig('javascripts', 'webpack', 'resolve', 'extensions');
|
|
19
|
-
const ignore = getConfig.getTaskConfig('javascripts', 'ignore');
|
|
19
|
+
const extensions = getConfig.getTaskConfig('javascripts', '0', 'webpack', 'resolve', 'extensions');
|
|
20
|
+
const ignore = getConfig.getTaskConfig('javascripts', '0', 'ignore');
|
|
20
21
|
|
|
21
22
|
return globs.generate(
|
|
22
23
|
globs.paths(sourcePaths).filesWithExtensions(extensions), // Files to watch
|
|
@@ -26,19 +27,42 @@ const getGlobPaths = memoize(function () {
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
function javascripts (watch) {
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
const configs = getConfig.getTaskConfig('javascripts');
|
|
31
|
+
|
|
32
|
+
// Configs is an array, for each of the entry files separate config is created
|
|
33
|
+
const tasks = configs.map(function (config, index) {
|
|
34
|
+
// Gulp task function
|
|
35
|
+
const fn = function () {
|
|
36
|
+
return gulp.src(getGlobPaths())
|
|
37
|
+
.pipe(taskStart())
|
|
38
|
+
|
|
39
|
+
.pipe(gulpWebpack(
|
|
40
|
+
merge(config.webpack, {'watch': watch === true}),
|
|
41
|
+
webpack
|
|
42
|
+
))
|
|
43
|
+
|
|
44
|
+
.pipe(taskBeforeDest())
|
|
45
|
+
.pipe(gulp.dest(getPaths.getDestPath('javascripts')))
|
|
31
46
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
))
|
|
47
|
+
// Reload on change
|
|
48
|
+
.pipe(taskEnd());
|
|
49
|
+
};
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
// Set name of the gulp task function, currently it doesn't have a name yet
|
|
52
|
+
// This is needed so that name appears in terminal when running build
|
|
53
|
+
let name = 'javascripts' + (watch ? 'Watch' : '');
|
|
39
54
|
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
if (configs.length > 1) {
|
|
56
|
+
let entryFileName = config.entryList.name.replace('.json', '').replace('.js', '');
|
|
57
|
+
name += entryFileName[0].toUpperCase() + entryFileName.slice(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Object.defineProperty(fn, 'name', { value: name });
|
|
61
|
+
|
|
62
|
+
return fn;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return parallel(...tasks);
|
|
42
66
|
}
|
|
43
67
|
|
|
44
68
|
function javascriptsWatch () {
|
|
@@ -46,6 +70,6 @@ function javascriptsWatch () {
|
|
|
46
70
|
return javascripts(true);
|
|
47
71
|
}
|
|
48
72
|
|
|
49
|
-
|
|
50
|
-
exports.build = javascripts;
|
|
51
|
-
exports.watch = javascriptsWatch;
|
|
73
|
+
// Dynamic task will be executed when config is ready and must return gulp tasks
|
|
74
|
+
exports.build = dynamicTask(javascripts);
|
|
75
|
+
exports.watch = dynamicTask(javascriptsWatch);
|
|
@@ -45,8 +45,9 @@ test('Preprocess returning non-object should result in same config config', () =
|
|
|
45
45
|
const configString = {'task': {'a': 1}, 'preprocess': {'task': [() => 'string']}};
|
|
46
46
|
expect(runPreprocess(configString).task).toEqual({'a': 1});
|
|
47
47
|
|
|
48
|
+
// Task config can be an array, this is used for javascripts
|
|
48
49
|
const configArray = {'task': {'a': 1}, 'preprocess': {'task': [() => ['a', 'b']]}};
|
|
49
|
-
expect(runPreprocess(configArray).task).toEqual(
|
|
50
|
+
expect(runPreprocess(configArray).task).toEqual(['a', 'b']);
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
test('Preprocess returning false shouldn\'t call other preprocesses', () => {
|