@caweb/html-webpack-plugin 2.0.1 → 2.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.
- package/CHANGELOG.md +6 -0
- package/index.js +176 -140
- package/package.json +16 -9
- package/tests/webpack.tests.js +32 -0
package/CHANGELOG.md
CHANGED
package/index.js
CHANGED
|
@@ -15,10 +15,59 @@ const boldWhite = chalk.bold.white;
|
|
|
15
15
|
const boldGreen = chalk.bold.green;
|
|
16
16
|
const boldBlue = chalk.bold.hex('#03a7fc');
|
|
17
17
|
*/
|
|
18
|
-
|
|
18
|
+
// this is the current project directory
|
|
19
19
|
const appPath = process.cwd();
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
|
|
21
|
+
// this is the path to this current file
|
|
22
|
+
const currentPath = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
|
|
24
|
+
// this should be the path to the @caweb/template and @caweb/icon-library packages
|
|
25
|
+
const templatePath = path.join( 'node_modules', '@caweb', 'template');
|
|
26
|
+
const iconLibraryPath = path.join( 'node_modules', '@caweb', 'icon-library');
|
|
27
|
+
|
|
28
|
+
const allowedAssetExts = [
|
|
29
|
+
'.png', '.jpg', '.jpeg', '.gif', '.svg',
|
|
30
|
+
'.bmp', '.gif', '.ico',
|
|
31
|
+
'.woff', '.woff2', '.eot', '.ttf', '.otf'
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
// function to process assets from regex matches
|
|
35
|
+
const processAssets = ( assets = [] , type = 'style') => {
|
|
36
|
+
let temp = [];
|
|
37
|
+
|
|
38
|
+
if( ! assets ){
|
|
39
|
+
return temp;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if( 'style' === type ){
|
|
43
|
+
temp = assets
|
|
44
|
+
.map( a => {
|
|
45
|
+
return a
|
|
46
|
+
.replace(/(style=".*url\(\s*)(\S+)\s*\)/g, '$2') // get url() content
|
|
47
|
+
.replace(/((src|href)=")(\S+)".*/g, '$3') // remove src=" or href="
|
|
48
|
+
// .replace(/['"]/g, '') // remove quotes
|
|
49
|
+
})
|
|
50
|
+
} else {
|
|
51
|
+
temp = assets // map to extract just the asset file
|
|
52
|
+
.map( a => {
|
|
53
|
+
return a
|
|
54
|
+
.replace(/((src|href)=")/g, '') // remove src=" or href="
|
|
55
|
+
// .replace(/".*/g, '') // remove anything after the first "
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return temp
|
|
60
|
+
// filter to only include local files with allowed extensions
|
|
61
|
+
.filter( asset => {
|
|
62
|
+
let ext = path.extname( asset ).toLowerCase();
|
|
63
|
+
let localFile = fs.existsSync( path.join( appPath, asset ) )
|
|
64
|
+
|
|
65
|
+
return localFile && allowedAssetExts.includes( ext );
|
|
66
|
+
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const pluginName = 'CAWebHTMLPlugin';
|
|
22
71
|
|
|
23
72
|
/**
|
|
24
73
|
* Launches CAWeb HTML Markup
|
|
@@ -32,95 +81,97 @@ const iconLibraryPath = path.resolve(currentPath, '..', 'icon-library');
|
|
|
32
81
|
* @typedef {CAWebHTMLPlugin}
|
|
33
82
|
* @extends {HtmlWebpackPlugin}
|
|
34
83
|
*/
|
|
35
|
-
class
|
|
84
|
+
class CAWebHTMLPlugin extends HtmlWebpackPlugin{
|
|
36
85
|
|
|
37
86
|
// we change some of the html-webpack-plugin defaults
|
|
38
87
|
constructor(opts = {}) {
|
|
39
|
-
|
|
40
|
-
|
|
88
|
+
// the available templates in @caweb/template
|
|
89
|
+
let templates = ['blank', 'default', 'search'];
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Default options
|
|
93
|
+
* we use the @caweb/template package as the default template source
|
|
94
|
+
*
|
|
95
|
+
* @see https://github.com/jantimon/html-webpack-plugin/blob/main/index.js
|
|
96
|
+
*/
|
|
41
97
|
let defaultOptions = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
98
|
+
// we use the @caweb/template patterns/default.html as the default template
|
|
99
|
+
template: path.join( templatePath, 'patterns', 'default.html'),
|
|
100
|
+
|
|
101
|
+
// favicon
|
|
102
|
+
favicon: path.join( templatePath, 'media', 'favicon.ico' ),
|
|
103
|
+
|
|
104
|
+
// variables to pass to the template
|
|
46
105
|
templateParameters: {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
106
|
+
// site title
|
|
107
|
+
title: path.basename( appPath ),
|
|
108
|
+
|
|
109
|
+
//site color scheme
|
|
110
|
+
scheme: 'oceanside',
|
|
111
|
+
|
|
112
|
+
// site logo, default is the @caweb/template/media/logo.png
|
|
113
|
+
logo: path.join(templatePath, 'media', 'logo.png'),
|
|
114
|
+
|
|
115
|
+
// meta tags
|
|
116
|
+
meta: {
|
|
117
|
+
Author: "CAWebPublishing",
|
|
118
|
+
Description: "State of California",
|
|
119
|
+
Keywords: "CAWebPublishing, California, government",
|
|
120
|
+
viewport: "width=device-width, initial-scale=1.0, maximum-scale=2.0"
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// array of additional assets to include
|
|
124
|
+
// this might be removed in the future
|
|
125
|
+
assets: []
|
|
56
126
|
},
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
// array of additional assets to include
|
|
130
|
+
// this might be removed in the future
|
|
57
131
|
assets: []
|
|
58
|
-
}
|
|
132
|
+
};
|
|
59
133
|
|
|
60
134
|
// if there is a favicon.ico file in the media directory we use that
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
path.join(appPath, 'media', 'favicon.ico') :
|
|
64
|
-
path.join(templatePath, 'media', 'favicon.ico');
|
|
65
|
-
|
|
66
|
-
// the templateParameters.favicon is not set, set it
|
|
67
|
-
if( ! defaultOptions.templateParameters.favicon ){
|
|
68
|
-
defaultOptions.templateParameters.favicon = defaultOptions.favicon;
|
|
135
|
+
if( fs.existsSync(path.join(appPath, 'media', 'favicon.ico')) ){
|
|
136
|
+
defaultOptions.favicon = path.join(appPath, 'media', 'favicon.ico');
|
|
69
137
|
}
|
|
70
138
|
|
|
71
139
|
// if there is a logo file in the media directory we use that
|
|
72
140
|
if( fs.existsSync(path.join(appPath, 'media', 'logo.png')) ){
|
|
73
|
-
defaultOptions.assets.push( path.join(appPath, 'media', 'logo.png') );
|
|
141
|
+
// defaultOptions.assets.push( path.join(appPath, 'media', 'logo.png') );
|
|
74
142
|
defaultOptions.templateParameters.logo = '/media/logo.png';
|
|
75
|
-
|
|
76
|
-
// otherwise we fallback to the template logo.png
|
|
77
|
-
}else{
|
|
78
|
-
// remove the appPath from the templath path
|
|
79
|
-
// replace all backslashes with forward slashes
|
|
80
|
-
// this is to make sure the logo.png in the branding.html is in the right place
|
|
81
|
-
defaultOptions.templateParameters.logo =
|
|
82
|
-
path.join(
|
|
83
|
-
templatePath,
|
|
84
|
-
'media', 'logo.png'
|
|
85
|
-
)
|
|
86
|
-
.replace(appPath, '')
|
|
87
|
-
.replace(/\\/g, '/');
|
|
88
143
|
}
|
|
89
144
|
|
|
90
|
-
// update templateParameters.title to match user options.
|
|
91
|
-
if( opts.title ){
|
|
92
|
-
defaultOptions.templateParameters.title = opts.title;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
145
|
// if template selection is one of ours
|
|
96
146
|
if( opts.template && templates.includes(opts.template) ){
|
|
97
|
-
let template = 'default' === opts.template ? 'index' : opts.template;
|
|
98
147
|
|
|
99
148
|
// update template file based on template selection
|
|
100
|
-
opts.template = path.join( templatePath, 'patterns', `${template}.html`);
|
|
101
|
-
|
|
102
|
-
// update default.templateParameters.template to match user options.
|
|
103
|
-
defaultOptions.templateParameters.template = template;
|
|
149
|
+
opts.template = path.join( templatePath, 'patterns', `${opts.template}.html`);
|
|
104
150
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* the html-webpack-plugin meta tags are missing the self closing forward slash
|
|
154
|
+
* so if the user options has meta tags, we move them to the opts.templateParameters.meta
|
|
155
|
+
* and delete the opts.meta key
|
|
156
|
+
*/
|
|
108
157
|
if( opts.meta ){
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
...opts.meta
|
|
112
|
-
}
|
|
158
|
+
// ensure templateParameters exists
|
|
159
|
+
opts.templateParameters = opts.templateParameters || {};
|
|
113
160
|
|
|
161
|
+
// move opts.meta to opts.templateParameters.meta
|
|
162
|
+
opts.templateParameters.meta = opts.meta
|
|
163
|
+
|
|
164
|
+
// delete opts.meta
|
|
114
165
|
delete opts.meta;
|
|
115
166
|
}
|
|
116
167
|
|
|
117
168
|
// if there is a caweb.json file we merge the site data with the templateParameters
|
|
118
169
|
if( fs.existsSync( path.join(appPath, 'caweb.json') ) ){
|
|
119
|
-
|
|
120
170
|
let dataFile = JSON.parse( fs.readFileSync( path.join(appPath, 'caweb.json') ) );
|
|
121
|
-
|
|
171
|
+
|
|
122
172
|
// if there is a dataFile.site
|
|
123
173
|
if( dataFile.site ){
|
|
174
|
+
|
|
124
175
|
// we remove the title key from the dataFile.site
|
|
125
176
|
// this is to avoid overwriting the title set in the defaultOptions.templateParameters
|
|
126
177
|
if( dataFile.site.title ){
|
|
@@ -134,8 +185,8 @@ class CAWebHtmlWebpackPlugin extends HtmlWebpackPlugin{
|
|
|
134
185
|
...dataFile.site
|
|
135
186
|
}
|
|
136
187
|
|
|
137
|
-
// some properties are used in different ways and not as templateParameters
|
|
138
|
-
// if there is a dataFile.site.favicon we
|
|
188
|
+
// some properties are used in different ways and not just as templateParameters
|
|
189
|
+
// if there is a dataFile.site.favicon we have to define that outside of the templateParameters
|
|
139
190
|
if( dataFile.site.favicon ){
|
|
140
191
|
defaultOptions.favicon = dataFile.site.favicon;
|
|
141
192
|
}
|
|
@@ -143,6 +194,7 @@ class CAWebHtmlWebpackPlugin extends HtmlWebpackPlugin{
|
|
|
143
194
|
|
|
144
195
|
}
|
|
145
196
|
|
|
197
|
+
// call the parent class constructor with the merged options
|
|
146
198
|
super(deepmerge(defaultOptions, opts));
|
|
147
199
|
|
|
148
200
|
}
|
|
@@ -150,56 +202,40 @@ class CAWebHtmlWebpackPlugin extends HtmlWebpackPlugin{
|
|
|
150
202
|
apply(compiler) {
|
|
151
203
|
super.apply(compiler);
|
|
152
204
|
|
|
153
|
-
compiler.hooks.compilation.tap(
|
|
205
|
+
compiler.hooks.compilation.tap(pluginName, (compilation) => {
|
|
154
206
|
/**
|
|
155
207
|
* Hook into the HtmlWebpackPlugin events
|
|
156
208
|
*
|
|
157
209
|
* @link https://github.com/jantimon/html-webpack-plugin?tab=readme-ov-file#events
|
|
158
210
|
*/
|
|
159
211
|
HtmlWebpackPlugin.getCompilationHooks(compilation).beforeEmit.tapAsync(
|
|
160
|
-
|
|
212
|
+
pluginName,
|
|
161
213
|
({html, outputName, plugin}, cb) => {
|
|
162
214
|
// if the html contains local assets those assets are added to the options.assets array
|
|
163
215
|
// and the assets are added to the compilation afterEmit
|
|
164
|
-
let srcHrefAssets = html.match(/(src|href)="(
|
|
165
|
-
let styleAssets = html.match(/style=".*url\((\S+)\)/g);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
// if the asset is a local file
|
|
189
|
-
// if the asset is not already in the options.assets array
|
|
190
|
-
if(
|
|
191
|
-
fs.existsSync(localFile) &&
|
|
192
|
-
fs.lstatSync(localFile).isFile() &&
|
|
193
|
-
! this.options.assets.includes(localFile)
|
|
194
|
-
){
|
|
195
|
-
this.options.assets.push(localFile);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// any references to the node_modules directory are removed
|
|
200
|
-
// any organizational packages @ are also removed
|
|
201
|
-
// this might cause some conflicts with packages that are named the same as organiazational packages
|
|
202
|
-
html = html.replace(/[\\\/]?node_modules[\\\/@]+/g, '/');
|
|
216
|
+
// let srcHrefAssets = processAssets(html.match(/(src|href)="(.+)"/g));
|
|
217
|
+
// let styleAssets = processAssets(html.match(/style=".*url\((\S+)\)/g));
|
|
218
|
+
// let allAssets = [ ...new Set([
|
|
219
|
+
// ...srcHrefAssets,
|
|
220
|
+
// ...styleAssets
|
|
221
|
+
// ])
|
|
222
|
+
// ];
|
|
223
|
+
|
|
224
|
+
// allAssets.forEach( asset =>{
|
|
225
|
+
// let localFile = asset.startsWith('/') || asset.startsWith('\\') ?
|
|
226
|
+
// path.join( appPath, asset ) :
|
|
227
|
+
// asset;
|
|
228
|
+
|
|
229
|
+
// // if the asset is a local file
|
|
230
|
+
// // if the asset is not already in the options.assets array
|
|
231
|
+
// if(
|
|
232
|
+
// fs.existsSync(localFile) &&
|
|
233
|
+
// fs.lstatSync(localFile).isFile() &&
|
|
234
|
+
// ! this.options.assets.includes(localFile)
|
|
235
|
+
// ){
|
|
236
|
+
// this.options.assets.push(localFile);
|
|
237
|
+
// }
|
|
238
|
+
// });
|
|
203
239
|
|
|
204
240
|
// Tell webpack to move on
|
|
205
241
|
cb(null, {html, outputName, plugin});
|
|
@@ -207,46 +243,46 @@ class CAWebHtmlWebpackPlugin extends HtmlWebpackPlugin{
|
|
|
207
243
|
);
|
|
208
244
|
|
|
209
245
|
HtmlWebpackPlugin.getCompilationHooks(compilation).afterEmit.tapAsync(
|
|
210
|
-
|
|
246
|
+
pluginName,
|
|
211
247
|
({outputName, plugin}, cb) => {
|
|
212
248
|
|
|
213
249
|
// if there are any assets in the options.assets array
|
|
214
250
|
// we add them to the compilation and emit them
|
|
215
|
-
this.options.assets.forEach( async (asset) => {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
251
|
+
// this.options.assets.forEach( async (asset) => {
|
|
252
|
+
// compilation.fileDependencies.add( asset );
|
|
253
|
+
|
|
254
|
+
// // we remove the appPath from the asset path
|
|
255
|
+
// // we remove the node_modules/@ from the asset path
|
|
256
|
+
// compilation.emitAsset(
|
|
257
|
+
// asset.replace(appPath, '').replace(/[\\\/]?node_modules[\\\/@]+/g, ''),
|
|
258
|
+
// new compiler.webpack.sources.RawSource( fs.readFileSync(asset) )
|
|
259
|
+
// );
|
|
260
|
+
|
|
261
|
+
// // if the asset is the @caweb/icon-library font-only.css file we have to also add the font files
|
|
262
|
+
// if( asset.match(/@caweb\/icon-library\/build\/font-only-?.*.css/g) ){
|
|
263
|
+
// let fontPath = path.join( iconLibraryPath, 'build', 'fonts' );
|
|
264
|
+
|
|
265
|
+
// let fontFiles = fs.readdirSync(fontPath).filter( (file) => {
|
|
266
|
+
// return file.endsWith('.woff') ||
|
|
267
|
+
// file.endsWith('.woff2') ||
|
|
268
|
+
// file.endsWith('.eot') ||
|
|
269
|
+
// file.endsWith('.svg') ||
|
|
270
|
+
// file.endsWith('.ttf');
|
|
271
|
+
// });
|
|
272
|
+
|
|
273
|
+
// fontFiles.forEach( (file) => {
|
|
274
|
+
// compilation.fileDependencies.add( file );
|
|
275
|
+
|
|
276
|
+
// let filePath = path.join( fontPath, file );
|
|
241
277
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
278
|
+
// // we remove the appPath from the asset path
|
|
279
|
+
// compilation.emitAsset(
|
|
280
|
+
// filePath.replace(appPath, '').replace(/[\\\/]?node_modules[\\\/@]+/g, ''),
|
|
281
|
+
// new compiler.webpack.sources.RawSource( fs.readFileSync(filePath) )
|
|
282
|
+
// );
|
|
283
|
+
// });
|
|
284
|
+
// }
|
|
285
|
+
// });
|
|
250
286
|
|
|
251
287
|
// Tell webpack to move on
|
|
252
288
|
cb(null, {outputName, plugin});
|
|
@@ -258,4 +294,4 @@ class CAWebHtmlWebpackPlugin extends HtmlWebpackPlugin{
|
|
|
258
294
|
} // end of class
|
|
259
295
|
|
|
260
296
|
|
|
261
|
-
export default
|
|
297
|
+
export default CAWebHTMLPlugin;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caweb/html-webpack-plugin",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "CAWebPublishing Site Generation HTML Webpack Plugin",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
"author": "CAWebPublishing",
|
|
8
|
+
"license": "ISC",
|
|
9
|
+
"homepage": "https://github.com/CAWebPublishing/webpack/plugins/html#readme",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "git+https://github.com/CAWebPublishing/webpack.git",
|
|
@@ -18,19 +18,26 @@
|
|
|
18
18
|
"webpack",
|
|
19
19
|
"html-webpack-plugin"
|
|
20
20
|
],
|
|
21
|
-
"author": "CAWebPublishing",
|
|
22
|
-
"license": "ISC",
|
|
23
21
|
"bugs": {
|
|
24
22
|
"url": "https://github.com/CAWebPublishing/webpack/issues"
|
|
25
23
|
},
|
|
26
24
|
"publishConfig": {
|
|
27
25
|
"access": "public"
|
|
28
26
|
},
|
|
29
|
-
"homepage": "https://github.com/CAWebPublishing/webpack/plugins/html#readme",
|
|
30
27
|
"dependencies": {
|
|
28
|
+
"@caweb/framework": "^1.9.2",
|
|
29
|
+
"@caweb/icon-library": "^1.1.6",
|
|
30
|
+
"@caweb/template": "^1.0.12",
|
|
31
31
|
"html-webpack-plugin": "^5.6.6"
|
|
32
32
|
},
|
|
33
|
-
"
|
|
34
|
-
"
|
|
33
|
+
"scripts": {
|
|
34
|
+
"webpack": "webpack",
|
|
35
|
+
"test:build": "webpack build --config ./node_modules/@caweb/webpack/webpack.config.js",
|
|
36
|
+
"test:serve": "webpack serve --config ./node_modules/@caweb/webpack/webpack.config.js ./tests/webpack.tests.js --merge",
|
|
37
|
+
"test": "echo \"Error: run tests from root\" && exit 0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"webpack": "^5.104.1",
|
|
41
|
+
"webpack-cli": "^6.0.1"
|
|
35
42
|
}
|
|
36
43
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* These are tests for the CAWeb HTML Webpack Plugin
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* External Dependencies
|
|
7
|
+
*/
|
|
8
|
+
import path from 'path';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Internal Dependencies
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// we import this current plugin to test it
|
|
15
|
+
import CAWebHtmlWebpackPlugin from '../index.js';
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
plugins: [
|
|
19
|
+
new CAWebHtmlWebpackPlugin({
|
|
20
|
+
templateParameters: {
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
],
|
|
24
|
+
devServer: {
|
|
25
|
+
static: [
|
|
26
|
+
// we all serving the local template media files for testing
|
|
27
|
+
{
|
|
28
|
+
directory: path.join( process.cwd(), '..', 'template', 'media' ),
|
|
29
|
+
},
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
};
|