@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 CHANGED
@@ -1,3 +1,9 @@
1
+ v2.1.0
2
+ - Plugin name was changed
3
+
4
+ v2.0.2
5
+ - No longer emitting src/href/styles assets
6
+
1
7
  v2.0.1
2
8
  - Updated npm packages
3
9
 
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
- const currentPath = path.dirname(fileURLToPath(import.meta.url));
18
+ // this is the current project directory
19
19
  const appPath = process.cwd();
20
- const templatePath = path.resolve(currentPath, '..', 'template');
21
- const iconLibraryPath = path.resolve(currentPath, '..', 'icon-library');
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 CAWebHtmlWebpackPlugin extends HtmlWebpackPlugin{
84
+ class CAWebHTMLPlugin extends HtmlWebpackPlugin{
36
85
 
37
86
  // we change some of the html-webpack-plugin defaults
38
87
  constructor(opts = {}) {
39
- let templates = ['index', 'blank', 'default', 'search'];
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
- title: path.basename( appPath ),
43
- inject: 'body',
44
- template: path.join( templatePath, 'patterns', 'index.html'),
45
- scriptLoading: 'blocking',
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
- "template": "index",
48
- "title": path.basename( appPath ),
49
- "scheme": "oceanside",
50
- "meta": {
51
- "Author": "CAWebPublishing",
52
- "Description": "State of California",
53
- "Keywords": "California,government",
54
- "viewport": "width=device-width, initial-scale=1.0, maximum-scale=2.0"
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
- // otherwise we fallback to the template favicon.ico
62
- defaultOptions.favicon = fs.existsSync(path.join(appPath, 'media', 'favicon.ico')) ?
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
- // if the user options has meta tags we merge them with the defaultOptions.templateParameters.meta
107
- // and clear the meta key
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
- defaultOptions.templateParameters.meta = {
110
- ...defaultOptions.templateParameters.meta,
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 use that
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("CAWebHtmlWebpackPlugin", (compilation) => {
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
- "CAWebHtmlWebpackPlugin",
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)="(.+?)"/g);
165
- let styleAssets = html.match(/style=".*url\((\S+)\)/g);
166
-
167
- let allAssets = [];
168
-
169
- // if the html contains url() in the style attributes
170
- if( styleAssets ){
171
- styleAssets = styleAssets.map( s => s.replace(/(style=".*url\(|["'()])/g, '') )
172
- // |["'\(\)]
173
- allAssets = [...allAssets, ...styleAssets];
174
- }
175
-
176
- // if the html contains src or href attributes
177
- if( srcHrefAssets ){
178
- srcHrefAssets = srcHrefAssets.map( s => s.replace(/(src|href|=|")/g, '') );
179
-
180
- allAssets = [...allAssets, ...srcHrefAssets];
181
- }
182
-
183
- allAssets.forEach( asset =>{
184
- let localFile = asset.startsWith('/') || asset.startsWith('\\') ?
185
- path.join( appPath, asset ) :
186
- asset;
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
- "CAWebHtmlWebpackPlugin",
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
- compilation.fileDependencies.add( asset );
217
-
218
- // we remove the appPath from the asset path
219
- // we remove the node_modules/@ from the asset path
220
- compilation.emitAsset(
221
- asset.replace(appPath, '').replace(/[\\\/]?node_modules[\\\/@]+/g, ''),
222
- new compiler.webpack.sources.RawSource( fs.readFileSync(asset) )
223
- );
224
-
225
- // if the asset is the @caweb/icon-library font-only.css file we have to also add the font files
226
- if( asset.match(/@caweb\/icon-library\/build\/font-only-?.*.css/g) ){
227
- let fontPath = path.join( iconLibraryPath, 'build', 'fonts' );
228
-
229
- let fontFiles = fs.readdirSync(fontPath).filter( (file) => {
230
- return file.endsWith('.woff') ||
231
- file.endsWith('.woff2') ||
232
- file.endsWith('.eot') ||
233
- file.endsWith('.svg') ||
234
- file.endsWith('.ttf');
235
- });
236
-
237
- fontFiles.forEach( (file) => {
238
- compilation.fileDependencies.add( file );
239
-
240
- let filePath = path.join( fontPath, file );
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
- // we remove the appPath from the asset path
243
- compilation.emitAsset(
244
- filePath.replace(appPath, '').replace(/[\\\/]?node_modules[\\\/@]+/g, ''),
245
- new compiler.webpack.sources.RawSource( fs.readFileSync(filePath) )
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 CAWebHtmlWebpackPlugin;
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.1",
3
+ "version": "2.1.0",
4
4
  "description": "CAWebPublishing Site Generation HTML Webpack Plugin",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
- "scripts": {
8
- "test": "echo \"Error: run tests from root\" && exit 0"
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
- "peerDependencies": {
34
- "@caweb/template": "^1.0.6"
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
+ };