@caweb/webpack 1.5.17 → 1.6.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/lib/args.js +46 -0
- package/lib/loader.js +117 -0
- package/lib/server.js +134 -0
- package/lib/webpack.wp.config.js +99 -0
- package/package.json +13 -19
- package/tests/caweb.json +54 -0
- package/tests/webpack.tests.js +106 -0
- package/webpack.config.js +138 -414
package/lib/args.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// flags can be passed via argv0
|
|
2
|
+
// we also add args from NODE_OPTIONS
|
|
3
|
+
let flags = [].concat(
|
|
4
|
+
processArgs(process.argv),
|
|
5
|
+
processArgs(process.argv0.split(' ')),
|
|
6
|
+
processArgs(process.env.NODE_OPTIONS ? process.env.NODE_OPTIONS.split(' ') : []),
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// this function processes an array of arguments
|
|
10
|
+
// and returns an array of flags and values
|
|
11
|
+
function processArgs( arr ){
|
|
12
|
+
let tmp = [];
|
|
13
|
+
|
|
14
|
+
arr.filter(Boolean).map((o) => {
|
|
15
|
+
return o.replaceAll("'", '').split('=').forEach((e => tmp.push(e)))
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return tmp
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// function to add a flag
|
|
22
|
+
function addFlag(flag, value = null){
|
|
23
|
+
if( ! flagExists(flag) ){
|
|
24
|
+
flags.push(flag);
|
|
25
|
+
if( value ){
|
|
26
|
+
flags.push(value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// check if a flag exists
|
|
32
|
+
function flagExists(flag){
|
|
33
|
+
return flags.includes(flag)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// get the value of a flag
|
|
37
|
+
function getArgVal(flag, defaultValue = null){
|
|
38
|
+
return flagExists(flag) ? flags[flags.indexOf(flag) + 1] : (defaultValue ?? false);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
flags,
|
|
43
|
+
flagExists,
|
|
44
|
+
addFlag,
|
|
45
|
+
getArgVal
|
|
46
|
+
};
|
package/lib/loader.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Various loader options for webpack handlebars loader.
|
|
3
|
+
* @see https://github.com/pcardune/handlebars-loader
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
|
|
10
|
+
const currentPath = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const appPath = process.cwd();
|
|
12
|
+
const helperDirs = [...new Set([
|
|
13
|
+
getAllHelpers( path.join( currentPath, '..', 'helpers') ),// our loader helpers
|
|
14
|
+
fs.existsSync( path.join( appPath, 'helpers') ) ? // any custom helpers
|
|
15
|
+
[
|
|
16
|
+
path.join( appPath, 'helpers'),
|
|
17
|
+
...getAllHelpers( path.join( appPath, 'helpers') ),
|
|
18
|
+
] : []
|
|
19
|
+
].flat())];
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// function to resolve partials
|
|
23
|
+
const partialResolver = ( partial, callback ) => {
|
|
24
|
+
// fallback path to the @caweb/template package
|
|
25
|
+
const fallbackPath = path.join( currentPath, '..', '..', 'template' );
|
|
26
|
+
|
|
27
|
+
let partialDir = '';
|
|
28
|
+
|
|
29
|
+
// template parameter specific partials
|
|
30
|
+
switch ( partial ) {
|
|
31
|
+
/**
|
|
32
|
+
* Semantic elements are served from the /semantic/ directory
|
|
33
|
+
*
|
|
34
|
+
* - header
|
|
35
|
+
* - footer
|
|
36
|
+
*
|
|
37
|
+
* @link https://www.w3schools.com/html/html5_semantic_elements.asp
|
|
38
|
+
*/
|
|
39
|
+
case 'branding':
|
|
40
|
+
case 'footer':
|
|
41
|
+
case 'header':
|
|
42
|
+
case 'mobileControls':
|
|
43
|
+
case 'navFooter':
|
|
44
|
+
case 'navHeader':
|
|
45
|
+
case 'utilityHeader':
|
|
46
|
+
partialDir = 'semantics';
|
|
47
|
+
break;
|
|
48
|
+
|
|
49
|
+
// content is served from the /content/ directory
|
|
50
|
+
case 'index':
|
|
51
|
+
case 'content':
|
|
52
|
+
partialDir = 'content';
|
|
53
|
+
break;
|
|
54
|
+
|
|
55
|
+
// components are served from the /components/ directory
|
|
56
|
+
case 'alert':
|
|
57
|
+
case 'card':
|
|
58
|
+
partialDir = `components/${partial}`;
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
// forms are served from the /forms/ directory
|
|
62
|
+
case 'searchForm':
|
|
63
|
+
partialDir = 'forms';
|
|
64
|
+
break;
|
|
65
|
+
|
|
66
|
+
// tables are served from the /tables/ directory
|
|
67
|
+
case partial.includes('Table'):
|
|
68
|
+
partialDir = 'tables';
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// if the partial was mapped to specific directories under the @caweb/template
|
|
73
|
+
if( partialDir ){
|
|
74
|
+
// we remove the Form from the name
|
|
75
|
+
// we remove the Table from the name
|
|
76
|
+
// we change the partial name from camelCase to dash-case
|
|
77
|
+
partial = partial.replace(/(Form|Table)/, '').replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
78
|
+
|
|
79
|
+
// if the partial exists in the appPath, use that first
|
|
80
|
+
// otherwise use the template path
|
|
81
|
+
if( fs.existsSync( path.join( appPath, partialDir, `/${partial}.html` ) ) ){
|
|
82
|
+
partial = path.join( appPath, partialDir, `/${partial}.html` );
|
|
83
|
+
|
|
84
|
+
// if the @caweb/template is installed we use that as the fallback
|
|
85
|
+
} else if( fs.existsSync( path.join( fallbackPath, partialDir, `/${partial}.html` ) ) ) {
|
|
86
|
+
partial = path.join( fallbackPath, partialDir, `/${partial}.html` );
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
callback(false, partial );
|
|
91
|
+
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// get all helpers in a given path
|
|
95
|
+
function getAllHelpers( helpersPath ) {
|
|
96
|
+
return fs.readdirSync(
|
|
97
|
+
helpersPath,
|
|
98
|
+
{
|
|
99
|
+
withFileTypes: true ,
|
|
100
|
+
recursive: true
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
.filter( dirent => dirent.isDirectory() )
|
|
104
|
+
.map( dirent => path.join( dirent.parentPath, dirent.name ) );
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default {
|
|
108
|
+
// rootRelative: appPath,
|
|
109
|
+
partialResolver,
|
|
110
|
+
helperDirs,
|
|
111
|
+
precompileOptions: {
|
|
112
|
+
// prevent certain helpers from being precompiled
|
|
113
|
+
knownHelpersOnly: false,
|
|
114
|
+
preventIndent: true,
|
|
115
|
+
},
|
|
116
|
+
extensions: ['.html', '.handlebars', '.hbs', '' ],
|
|
117
|
+
};
|
package/lib/server.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is used base configuration DevServer settings for Webpack
|
|
3
|
+
*
|
|
4
|
+
* @see https://webpack.js.org/configuration/dev-server/
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* External dependencies
|
|
8
|
+
*/
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
|
|
12
|
+
const appPath = process.cwd();
|
|
13
|
+
|
|
14
|
+
// default url
|
|
15
|
+
let server = 'http';
|
|
16
|
+
let host = 'localhost';
|
|
17
|
+
let port = 9000;
|
|
18
|
+
|
|
19
|
+
// list of project directories to watch for changes
|
|
20
|
+
// by default css/js files are watched by webpack
|
|
21
|
+
// these directories are also added to the static file serving with watch true
|
|
22
|
+
let watchFiles = fs.readdirSync(
|
|
23
|
+
path.join( appPath ),
|
|
24
|
+
{
|
|
25
|
+
withFileTypes: true,
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
.filter( (dirent) => {
|
|
29
|
+
// we exclude certain directories from being watched
|
|
30
|
+
let file = path.join( dirent.parentPath, dirent.name );
|
|
31
|
+
let excluded = file.startsWith( `${appPath}\\build`) ||
|
|
32
|
+
file.startsWith( `${appPath}\\src`) ||
|
|
33
|
+
file.includes( `\\.`) ||
|
|
34
|
+
file.includes( 'vendor' ) ||
|
|
35
|
+
file.includes( 'node_modules' );
|
|
36
|
+
|
|
37
|
+
return dirent.isDirectory() && ! excluded
|
|
38
|
+
})
|
|
39
|
+
.map( dirent => path.join( dirent.parentPath, dirent.name, '**', '*').replace(/\\/g, '/') )
|
|
40
|
+
|
|
41
|
+
// base dev server config
|
|
42
|
+
let devServer = {
|
|
43
|
+
server,
|
|
44
|
+
host,
|
|
45
|
+
port,
|
|
46
|
+
open: [ `${server}://${host}:${port}` ],
|
|
47
|
+
|
|
48
|
+
static: [
|
|
49
|
+
/**
|
|
50
|
+
* Static files are served from the following files in the following order
|
|
51
|
+
* we don't have to add the build directory since that is the output.path and proxied
|
|
52
|
+
*
|
|
53
|
+
* node_modules - Allows loading files from other npm packages
|
|
54
|
+
* media - Allows loading media files from the media directory
|
|
55
|
+
*/
|
|
56
|
+
{
|
|
57
|
+
directory: path.join(appPath, 'node_modules'),
|
|
58
|
+
watch: false,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
directory: path.join(appPath, 'media'),
|
|
62
|
+
watch: false,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
|
|
66
|
+
proxy:[
|
|
67
|
+
/**
|
|
68
|
+
* WordPress Proxy Configuration is deprecated
|
|
69
|
+
* @since 31.3.0
|
|
70
|
+
*/
|
|
71
|
+
{
|
|
72
|
+
context: ['/build'],
|
|
73
|
+
target: `${server}://${host}:${port}`,
|
|
74
|
+
pathRewrite: {
|
|
75
|
+
'^/build': ''
|
|
76
|
+
},
|
|
77
|
+
logLevel: 'info'
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* We proxy the node_modules and media directory so they serve from the root
|
|
81
|
+
*/
|
|
82
|
+
{
|
|
83
|
+
context: ['/node_modules'],
|
|
84
|
+
target: `${server}://${host}:${port}`,
|
|
85
|
+
pathRewrite: { '^/node_modules': '' },
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
context: ['/media'],
|
|
89
|
+
target: `${server}://${host}:${port}`,
|
|
90
|
+
pathRewrite: { '^/media': '' },
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
|
|
94
|
+
liveReload: true,
|
|
95
|
+
hot: true,
|
|
96
|
+
|
|
97
|
+
// watchFiles
|
|
98
|
+
// we watch all folders in the app except build, node_modules and src
|
|
99
|
+
watchFiles: {
|
|
100
|
+
paths: watchFiles,
|
|
101
|
+
options: {
|
|
102
|
+
depth: 2,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// function to get the server config
|
|
108
|
+
const getServer = () => {
|
|
109
|
+
return devServer;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// function to add to the server config
|
|
113
|
+
const addToServer = ( key, value ) => {
|
|
114
|
+
devServer[ key ] = value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// function to update target url settings
|
|
118
|
+
const updateTarget = ( url ) => {
|
|
119
|
+
// update which url to open
|
|
120
|
+
devServer.open = [ url ];
|
|
121
|
+
|
|
122
|
+
// update all the proxy targets
|
|
123
|
+
devServer.proxy = devServer.proxy.map( ( proxy ) => {
|
|
124
|
+
proxy.target = url;
|
|
125
|
+
return proxy;
|
|
126
|
+
} );
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export {
|
|
131
|
+
getServer,
|
|
132
|
+
addToServer,
|
|
133
|
+
updateTarget
|
|
134
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modified WordPress Scripts Webpack Configuration
|
|
3
|
+
*
|
|
4
|
+
* @package CAWebPublishing
|
|
5
|
+
* @link https://webpack.js.org/configuration/
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* External Dependencies
|
|
10
|
+
*/
|
|
11
|
+
import baseConfig from '@wordpress/scripts/config/webpack.config.js';
|
|
12
|
+
import { getArgVal } from './args.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Internal dependencies
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Wordpress ignores the webpack --mode flag
|
|
19
|
+
// if the flag is passed we use that mode
|
|
20
|
+
// otherwise use whatever Wordpress is using
|
|
21
|
+
let mode = getArgVal('--mode') ? getArgVal('--mode') : baseConfig.mode;
|
|
22
|
+
let isProduction = mode === 'production';
|
|
23
|
+
|
|
24
|
+
// Update some of the default WordPress webpack rules.
|
|
25
|
+
baseConfig.module.rules.forEach((rule, i) => {
|
|
26
|
+
const r = new RegExp(rule.test).toString();
|
|
27
|
+
|
|
28
|
+
switch(r){
|
|
29
|
+
// WordPress adds a hash to asset file names we remove that hash.
|
|
30
|
+
case new RegExp(/\.(bmp|png|jpe?g|gif|webp)$/i).toString():
|
|
31
|
+
rule.generator.filename = 'images/[name][ext]';
|
|
32
|
+
break;
|
|
33
|
+
case new RegExp(/\.(woff|woff2|eot|ttf|otf)$/i).toString():
|
|
34
|
+
rule.generator.filename = 'fonts/[name][ext]';
|
|
35
|
+
break;
|
|
36
|
+
case new RegExp(/\.svg$/).toString():
|
|
37
|
+
// we don't want SVG to be asset/inline otherwise the resource may not be available.
|
|
38
|
+
// the asset should be an asset/resource we move them to the fonts folder.
|
|
39
|
+
if( 'asset/inline' === rule.type ){
|
|
40
|
+
rule.type = 'asset/resource';
|
|
41
|
+
rule.generator = { filename: 'fonts/[name][ext]' };
|
|
42
|
+
|
|
43
|
+
delete rule.issuer;
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
// silence deprecation warnings from sass
|
|
47
|
+
case new RegExp(/\.(sc|sa)ss$/).toString():
|
|
48
|
+
rule.use[rule.use.length-1].options.sassOptions = {
|
|
49
|
+
silenceDeprecations: ['global-builtin', 'import', 'color-functions', 'if-function']
|
|
50
|
+
};
|
|
51
|
+
break;
|
|
52
|
+
case new RegExp(/\.m?(j|t)sx?$/).toString():
|
|
53
|
+
// @since @wordpress/scripts@30.20.0 babel-loader is used for js and ts files
|
|
54
|
+
|
|
55
|
+
// Added the Transform class properties syntax plugin to the babel-loader.
|
|
56
|
+
// @see https://babeljs.io/docs/en/babel-plugin-proposal-class-properties
|
|
57
|
+
rule.use[0].options.plugins.push('@babel/plugin-proposal-class-properties');
|
|
58
|
+
|
|
59
|
+
// we add thread-loader before the babel-loader
|
|
60
|
+
// Spawns multiple processes and split work between them. This makes faster build.
|
|
61
|
+
// @see https://webpack.js.org/loaders/thread-loader/
|
|
62
|
+
rule.use = [{
|
|
63
|
+
loader: 'thread-loader',
|
|
64
|
+
options: {
|
|
65
|
+
workers: -1,
|
|
66
|
+
},
|
|
67
|
+
}].concat(rule.use);
|
|
68
|
+
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Update some of the default WordPress plugins.
|
|
74
|
+
baseConfig.plugins = baseConfig.plugins.map((plugin, i) => {
|
|
75
|
+
const pluginName = plugin.constructor.name;
|
|
76
|
+
|
|
77
|
+
switch(pluginName){
|
|
78
|
+
case 'MiniCssExtractPlugin':
|
|
79
|
+
// we change the default naming of the CSS files
|
|
80
|
+
plugin.options.filename = isProduction ? '[name].min.css' : '[name].css';
|
|
81
|
+
break;
|
|
82
|
+
case 'RtlCssPlugin':
|
|
83
|
+
// we disable the RTL CSS generation
|
|
84
|
+
plugin = false;
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return plugin;
|
|
90
|
+
}).filter( Boolean );
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* we remove the WordPress devServer declaration since we can only have 1 when exporting multiple configurations
|
|
94
|
+
*
|
|
95
|
+
* @see https://github.com/webpack/webpack-cli/issues/2408#issuecomment-793052542
|
|
96
|
+
*/
|
|
97
|
+
delete baseConfig.devServer;
|
|
98
|
+
|
|
99
|
+
export default baseConfig;
|
package/package.json
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caweb/webpack",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "CAWebPublishing Webpack Configuration",
|
|
5
5
|
"main": "webpack.config.js",
|
|
6
6
|
"files": [
|
|
7
|
+
"helpers",
|
|
8
|
+
"lib",
|
|
9
|
+
"tests",
|
|
7
10
|
"webpack.config.js",
|
|
8
|
-
"tsconfig.json"
|
|
9
|
-
"helpers"
|
|
11
|
+
"tsconfig.json"
|
|
10
12
|
],
|
|
11
13
|
"type": "module",
|
|
12
14
|
"scripts": {
|
|
13
15
|
"webpack": "webpack",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
+
"test:config": "webpack configtest",
|
|
17
|
+
"test:serve": "set NODE_OPTIONS='--template ./patterns/default.html --search-template ./patterns/search.html' && webpack serve --config ./webpack.config.js ./tests/webpack.tests.js --merge",
|
|
16
18
|
"test": "echo \\\"Error: run tests from root\\\" && exit 0"
|
|
17
19
|
},
|
|
18
20
|
"repository": {
|
|
@@ -35,28 +37,20 @@
|
|
|
35
37
|
"homepage": "https://github.com/CAWebPublishing/webpack#readme",
|
|
36
38
|
"dependencies": {
|
|
37
39
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
38
|
-
"@wordpress/scripts": "^31.
|
|
40
|
+
"@wordpress/scripts": "^31.3.0",
|
|
39
41
|
"css-minimizer-webpack-plugin": "^7.0.4",
|
|
42
|
+
"deepmerge": "^4.3.1",
|
|
43
|
+
"handlebars": "^4.7.8",
|
|
40
44
|
"handlebars-loader": "^1.7.3",
|
|
41
45
|
"html-format": "^1.1.7",
|
|
42
|
-
"html-webpack-
|
|
46
|
+
"html-webpack-plugin": "^5.6.6",
|
|
43
47
|
"html-webpack-skip-assets-plugin": "^1.0.4",
|
|
44
|
-
"mini-css-extract-plugin": "^2.9.4",
|
|
45
|
-
"rtlcss-webpack-plugin": "^4.0.7",
|
|
46
48
|
"thread-loader": "^4.0.4",
|
|
47
49
|
"ts-loader": "^9.5.4",
|
|
48
50
|
"webpack": "^5.104.1",
|
|
51
|
+
"webpack-cli": "^6.0.1",
|
|
49
52
|
"webpack-dev-server": "^5.2.3",
|
|
53
|
+
"webpack-merge": "^6.0.1",
|
|
50
54
|
"webpack-remove-empty-scripts": "^1.1.1"
|
|
51
|
-
},
|
|
52
|
-
"peerDependencies": {
|
|
53
|
-
"@caweb/a11y-webpack-plugin": ">= 2.0.0",
|
|
54
|
-
"@caweb/css-audit-webpack-plugin": ">= 2.0.0",
|
|
55
|
-
"@caweb/html-webpack-plugin": ">= 2.0.0",
|
|
56
|
-
"@caweb/jshint-webpack-plugin": ">= 2.0.0",
|
|
57
|
-
"html-webpack-plugin": ">= 3.0.0 < 5.6.5"
|
|
58
|
-
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"webpack-cli": "^6.0.1"
|
|
61
55
|
}
|
|
62
56
|
}
|
package/tests/caweb.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "This is a sample caweb.json configuration file for CAWebPublishing projects.",
|
|
3
|
+
"site": {
|
|
4
|
+
"domain": "http://localhost:9000",
|
|
5
|
+
"logo": "./media/logo.png",
|
|
6
|
+
"favicon": "./media/favicon.ico",
|
|
7
|
+
"header": {
|
|
8
|
+
"utility": {
|
|
9
|
+
"links": []
|
|
10
|
+
},
|
|
11
|
+
"nav": [
|
|
12
|
+
{
|
|
13
|
+
"label": "CAWebPublishing",
|
|
14
|
+
"url": "https://caweb.cdt.ca.gov/",
|
|
15
|
+
"sub":[]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"label": "CDT",
|
|
19
|
+
"url": "https://cdt.ca.gov/",
|
|
20
|
+
"sub": [
|
|
21
|
+
{
|
|
22
|
+
"label": "Accessibility",
|
|
23
|
+
"url": "https://caweb.cdt.ca.gov/accessibility-2/",
|
|
24
|
+
"description": "Accessibility"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"footer":{
|
|
31
|
+
"nav": [
|
|
32
|
+
{
|
|
33
|
+
"label": "Accessibility",
|
|
34
|
+
"url": "https://caweb.cdt.ca.gov/accessibility-2/"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"social": {
|
|
39
|
+
"github": "https://github.com/CAWebPublishing/"
|
|
40
|
+
},
|
|
41
|
+
"google": {
|
|
42
|
+
"search": "<Google Custom Search ID>"
|
|
43
|
+
},
|
|
44
|
+
"alerts": [
|
|
45
|
+
{
|
|
46
|
+
"icon": "info",
|
|
47
|
+
"header": "Dev Notice:",
|
|
48
|
+
"msg": "To see more CAWebPublishing projects, visit our Github Organization.",
|
|
49
|
+
"url": "https://github.com/CAWebPublishing/",
|
|
50
|
+
"text": "Visit Github"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* These are tests for the CAWebPublishing Template
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* External Dependencies
|
|
7
|
+
*/
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
|
12
|
+
import deepmerge from 'deepmerge';
|
|
13
|
+
import Handlebars from 'handlebars';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Internal Dependencies
|
|
17
|
+
*/
|
|
18
|
+
import { getArgVal } from '../lib/args.js';
|
|
19
|
+
|
|
20
|
+
// this is the path to the current project directory
|
|
21
|
+
const appPath = process.cwd();
|
|
22
|
+
|
|
23
|
+
// this is the path to this current file
|
|
24
|
+
const currentPath = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
|
|
26
|
+
// we read the test data caweb.json file
|
|
27
|
+
let testCaweb = JSON.parse( fs.readFileSync( path.join(currentPath, 'caweb.json') ) );
|
|
28
|
+
|
|
29
|
+
// we read the app caweb.json file if it exists
|
|
30
|
+
let defaultCaweb = fs.existsSync( path.join(appPath, 'caweb.json') ) ?
|
|
31
|
+
JSON.parse(fs.readFileSync(path.join(appPath, 'caweb.json')))
|
|
32
|
+
: {};
|
|
33
|
+
|
|
34
|
+
// merge the two caweb.json files, with the project data taking precedence
|
|
35
|
+
let caweb = deepmerge( testCaweb, defaultCaweb );
|
|
36
|
+
|
|
37
|
+
let templatePath = path.join(appPath, 'node_modules', '@caweb', 'template');
|
|
38
|
+
let template = getArgVal( '--template', path.join(templatePath, 'patterns', 'default.html') );
|
|
39
|
+
let searchTemplate = getArgVal( '--search-template', path.join(templatePath, 'patterns', 'search.html') );
|
|
40
|
+
|
|
41
|
+
let scheme = getArgVal( '--scheme', 'oceanside' );
|
|
42
|
+
let favicon = caweb?.site?.favicon ?? null;
|
|
43
|
+
|
|
44
|
+
// // Additional pages directory
|
|
45
|
+
let basePageDir = path.join(appPath, 'content', 'pages');
|
|
46
|
+
|
|
47
|
+
let additionalPages = ! fs.existsSync( basePageDir ) ? [] :
|
|
48
|
+
fs.readdirSync( basePageDir, { withFileTypes: true, recursive: true } )
|
|
49
|
+
.filter( dirent => dirent.isFile() && (dirent.name.endsWith('.html') || dirent.name.endsWith('.handlebars')) )
|
|
50
|
+
.map( ( dirent ) => {
|
|
51
|
+
|
|
52
|
+
let fileTemplate = path.join( dirent.parentPath, dirent.name );
|
|
53
|
+
|
|
54
|
+
// replace .html, uppercase the first letter of each word
|
|
55
|
+
// this is to make sure the title is readable
|
|
56
|
+
// and not just a file name
|
|
57
|
+
let title = dirent.name.replace('.html', '').replace(/\b\w/g, c => c.toUpperCase());
|
|
58
|
+
let content = fs.readFileSync( fileTemplate, 'utf-8' );
|
|
59
|
+
let data = {
|
|
60
|
+
...caweb.site,
|
|
61
|
+
scheme
|
|
62
|
+
};
|
|
63
|
+
let compiler = Handlebars.compile( content );
|
|
64
|
+
let compiledContent = compiler(data);
|
|
65
|
+
|
|
66
|
+
return new HtmlWebpackPlugin({
|
|
67
|
+
template,
|
|
68
|
+
filename: dirent.name,
|
|
69
|
+
title,
|
|
70
|
+
templateParameters: {
|
|
71
|
+
...caweb.site, // we spread the site data found in the caweb.json file
|
|
72
|
+
scheme,
|
|
73
|
+
partial: compiledContent,
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export default {
|
|
80
|
+
plugins: [
|
|
81
|
+
// this plugin generates the main landing page using the template found in patterns/index.html
|
|
82
|
+
new HtmlWebpackPlugin({
|
|
83
|
+
template,
|
|
84
|
+
favicon,
|
|
85
|
+
templateParameters: {
|
|
86
|
+
...caweb.site, // we spread the site data found in the caweb.json file
|
|
87
|
+
scheme ,
|
|
88
|
+
}
|
|
89
|
+
}),
|
|
90
|
+
|
|
91
|
+
// this plugin generates Search Results page using the template found in patterns/search.html
|
|
92
|
+
caweb?.site?.google?.search ? new HtmlWebpackPlugin({
|
|
93
|
+
template: searchTemplate,
|
|
94
|
+
favicon,
|
|
95
|
+
filename: 'serp.html',
|
|
96
|
+
title: 'Search Results Page',
|
|
97
|
+
templateParameters: {
|
|
98
|
+
...caweb.site, // we spread the site data found in the caweb.json file
|
|
99
|
+
scheme
|
|
100
|
+
},
|
|
101
|
+
}) : false,
|
|
102
|
+
|
|
103
|
+
// this plugin generates additional pages under content/pages directory using the template found in patterns/index.html
|
|
104
|
+
...additionalPages
|
|
105
|
+
].filter(Boolean)
|
|
106
|
+
};
|
package/webpack.config.js
CHANGED
|
@@ -9,29 +9,33 @@
|
|
|
9
9
|
/**
|
|
10
10
|
* External Dependencies
|
|
11
11
|
*/
|
|
12
|
-
import baseConfig from '@wordpress/scripts/config/webpack.config.js';
|
|
12
|
+
// import baseConfig from '@wordpress/scripts/config/webpack.config.js';
|
|
13
|
+
import baseConfig from './lib/webpack.wp.config.js';
|
|
13
14
|
import fs from 'fs';
|
|
14
15
|
import path from 'path';
|
|
15
16
|
import { fileURLToPath } from 'url';
|
|
16
17
|
|
|
17
18
|
// webpack plugins
|
|
18
|
-
import
|
|
19
|
+
import { merge } from 'webpack-merge';
|
|
20
|
+
// import MiniCSSExtractPlugin from 'mini-css-extract-plugin';
|
|
19
21
|
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
|
20
|
-
import RtlCssPlugin from 'rtlcss-webpack-plugin';
|
|
21
|
-
import {HtmlWebpackSkipAssetsPlugin} from 'html-webpack-skip-assets-plugin';
|
|
22
|
-
import {HtmlWebpackLinkTypePlugin} from 'html-webpack-link-type-plugin';
|
|
23
22
|
import RemoveEmptyScriptsPlugin from 'webpack-remove-empty-scripts';
|
|
23
|
+
import {HtmlWebpackSkipAssetsPlugin} from 'html-webpack-skip-assets-plugin';
|
|
24
|
+
// import RtlCssPlugin from 'rtlcss-webpack-plugin';
|
|
25
|
+
// import {HtmlWebpackLinkTypePlugin} from 'html-webpack-link-type-plugin';
|
|
24
26
|
|
|
25
|
-
import JSHintPlugin from '@caweb/jshint-webpack-plugin';
|
|
26
|
-
import CSSAuditPlugin from '@caweb/css-audit-webpack-plugin';
|
|
27
|
-
import A11yPlugin from '@caweb/a11y-webpack-plugin';
|
|
27
|
+
// import JSHintPlugin from '@caweb/jshint-webpack-plugin';
|
|
28
|
+
// import CSSAuditPlugin from '@caweb/css-audit-webpack-plugin';
|
|
29
|
+
// import A11yPlugin from '@caweb/a11y-webpack-plugin';
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* Internal dependencies
|
|
31
|
-
|
|
32
|
-
import
|
|
33
|
-
import
|
|
33
|
+
*/
|
|
34
|
+
import { flags, flagExists, getArgVal, addFlag } from './lib/args.js';
|
|
35
|
+
import handlebarsLoaderOptions from './lib/loader.js';
|
|
36
|
+
import { addToServer, getServer, updateTarget } from './lib/server.js';
|
|
34
37
|
|
|
38
|
+
// determine the webpack command
|
|
35
39
|
const webpackCommand = 'build' === process.argv[2] ? 'build' : 'serve' ;
|
|
36
40
|
|
|
37
41
|
// this is the path to this current file
|
|
@@ -40,260 +44,104 @@ const currentPath = path.dirname(fileURLToPath(import.meta.url));
|
|
|
40
44
|
// this is the path to the current project directory
|
|
41
45
|
const appPath = process.cwd();
|
|
42
46
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
let flags = [].concat(
|
|
46
|
-
processArgs(process.argv),
|
|
47
|
-
processArgs(process.argv0.split(' ')),
|
|
48
|
-
processArgs(process.env.NODE_OPTIONS ? process.env.NODE_OPTIONS.split(' ') : []),
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
const cawebJson = fs.existsSync( path.join(appPath, 'caweb.json') ) ?
|
|
47
|
+
// we read the caweb.json file if it exists
|
|
48
|
+
let caweb = fs.existsSync( path.join(appPath, 'caweb.json') ) ?
|
|
52
49
|
JSON.parse(fs.readFileSync(path.join(appPath, 'caweb.json')))
|
|
53
50
|
: {};
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// only add the flags if the site domain is not localhost
|
|
60
|
-
if( 'localhost' !== siteDomain.host ){
|
|
61
|
-
// we add the site domain to the flags
|
|
62
|
-
flags.push(
|
|
63
|
-
`--host`, siteDomain.host,
|
|
64
|
-
'--server-type', siteDomain.protocol.replace(':', ''),
|
|
65
|
-
'--port', '' !== siteDomain.port ? cawebJson.site.port : 80, // default port is 80
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
function processArgs( arr ){
|
|
72
|
-
let tmp = [];
|
|
73
|
-
|
|
74
|
-
arr.filter(Boolean).map((o) => {
|
|
75
|
-
return o.replaceAll("'", '').split('=').forEach((e => tmp.push(e)))
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
return tmp
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function flagExists(flag){
|
|
82
|
-
return flags.includes(flag)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function getArgVal(flag){
|
|
86
|
-
return flagExists(flag) ? flags[flags.indexOf(flag) + 1] : false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Update some of the default WordPress webpack rules.
|
|
90
|
-
baseConfig.module.rules.forEach((rule, i) => {
|
|
91
|
-
const r = new RegExp(rule.test).toString();
|
|
92
|
-
|
|
93
|
-
switch(r){
|
|
94
|
-
// WordPress adds a hash to asset file names we remove that hash.
|
|
95
|
-
case new RegExp(/\.(bmp|png|jpe?g|gif|webp)$/i).toString():
|
|
96
|
-
rule.generator.filename = 'images/[name][ext]';
|
|
97
|
-
break;
|
|
98
|
-
case new RegExp(/\.(woff|woff2|eot|ttf|otf)$/i).toString():
|
|
99
|
-
rule.generator.filename = 'fonts/[name][ext]';
|
|
100
|
-
break;
|
|
101
|
-
case new RegExp(/\.svg$/).toString():
|
|
102
|
-
// we don't want SVG to be asset/inline otherwise the resource may not be available.
|
|
103
|
-
// the asset should be an asset/resource we move them to the fonts folder.
|
|
104
|
-
if( 'asset/inline' === rule.type ){
|
|
105
|
-
rule.type = 'asset/resource';
|
|
106
|
-
rule.generator = { filename: 'fonts/[name][ext]' };
|
|
107
|
-
|
|
108
|
-
delete rule.issuer;
|
|
109
|
-
}
|
|
110
|
-
break;
|
|
111
|
-
// silence deprecation warnings from sass
|
|
112
|
-
case new RegExp(/\.(sc|sa)ss$/).toString():
|
|
113
|
-
rule.use[rule.use.length-1].options.sassOptions = {
|
|
114
|
-
silenceDeprecations: ['global-builtin', 'import', 'color-functions', 'if-function']
|
|
115
|
-
};
|
|
116
|
-
break;
|
|
117
|
-
case new RegExp(/\.m?(j|t)sx?$/).toString():
|
|
118
|
-
// @since @wordpress/scripts@30.20.0 babel-loader is used for js and ts files
|
|
119
|
-
|
|
120
|
-
// Added the Transform class properties syntax plugin to the babel-loader.
|
|
121
|
-
// @see https://babeljs.io/docs/en/babel-plugin-proposal-class-properties
|
|
122
|
-
rule.use[0].options.plugins.push('@babel/plugin-proposal-class-properties');
|
|
123
|
-
|
|
124
|
-
// we add thread-loader before the babel-loader
|
|
125
|
-
// Spawns multiple processes and split work between them. This makes faster build.
|
|
126
|
-
// @see https://webpack.js.org/loaders/thread-loader/
|
|
127
|
-
rule.use = [{
|
|
128
|
-
loader: 'thread-loader',
|
|
129
|
-
options: {
|
|
130
|
-
workers: -1,
|
|
131
|
-
},
|
|
132
|
-
}].concat(rule.use);
|
|
133
|
-
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
});
|
|
52
|
+
let mode = getArgVal('--mode') ? getArgVal('--mode') : baseConfig.mode;
|
|
53
|
+
let isProduction = mode === 'production';
|
|
54
|
+
let devServer = false;
|
|
137
55
|
|
|
138
56
|
/**
|
|
139
|
-
*
|
|
57
|
+
* DevServer is only added during 'serve' command
|
|
140
58
|
*
|
|
141
|
-
* @see https://
|
|
59
|
+
* @see https://webpack.js.org/configuration/dev-server/
|
|
142
60
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
61
|
+
if( 'serve' === webpackCommand ){
|
|
62
|
+
// we use the caweb.json file to determine the site domain
|
|
63
|
+
if( caweb?.site?.domain ){
|
|
64
|
+
try {
|
|
65
|
+
let siteDomain = new URL(caweb.site.domain);
|
|
66
|
+
|
|
67
|
+
// only add the flags if the site domain is not localhost
|
|
68
|
+
if( 'localhost' !== siteDomain.hostname ){
|
|
69
|
+
addToServer( 'host', siteDomain.hostname );
|
|
70
|
+
addToServer( 'server', siteDomain.protocol.replace(':', '') );
|
|
71
|
+
|
|
72
|
+
// only add the port if it is specified
|
|
73
|
+
if( '' !== siteDomain.port ){
|
|
74
|
+
addToServer( 'port', siteDomain.port );
|
|
75
|
+
}
|
|
148
76
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
customTemplateHelpers = [ path.join(appPath, 'helpers') ];
|
|
152
|
-
|
|
153
|
-
// we add any subdirectories
|
|
154
|
-
fs.readdirSync(
|
|
155
|
-
path.join(
|
|
156
|
-
appPath, 'helpers'
|
|
157
|
-
),
|
|
158
|
-
{
|
|
159
|
-
withFileTypes: true,
|
|
160
|
-
recursive: true
|
|
161
|
-
}
|
|
162
|
-
)
|
|
163
|
-
.filter( Dirent => Dirent.isDirectory() )
|
|
164
|
-
.map( Dirent => customTemplateHelpers.push( path.resolve(Dirent.parentPath, Dirent.name) ) )
|
|
77
|
+
updateTarget( siteDomain.href );
|
|
78
|
+
}
|
|
165
79
|
|
|
166
|
-
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.error(`\x1b[31mInvalid URL in caweb.json site.domain: ${caweb.site.domain}\x1b[0m`);
|
|
82
|
+
console.error( '\x1b[31mEnsure the domain is a valid URL, e.g., https://example.com\x1b[0m' )
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
167
86
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
let mode = getArgVal('--mode') ? getArgVal('--mode') : baseConfig.mode;
|
|
87
|
+
// get the dev server config
|
|
88
|
+
devServer = getServer();
|
|
89
|
+
}
|
|
172
90
|
|
|
91
|
+
// main webpack configuration object
|
|
173
92
|
let webpackConfig = {
|
|
174
|
-
...baseConfig,
|
|
175
93
|
mode,
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// Turn off caching of generated modules and chunks.
|
|
179
|
-
// @see https://webpack.js.org/configuration/cache/
|
|
180
|
-
cache: false,
|
|
181
|
-
|
|
182
|
-
stats: {
|
|
183
|
-
errors: true,
|
|
184
|
-
},
|
|
94
|
+
// target: 'web',
|
|
95
|
+
name: isProduction ? 'compressed' : 'uncompressed',
|
|
185
96
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Output Configuration
|
|
99
|
+
* @see https://webpack.js.org/configuration/output/
|
|
100
|
+
*/
|
|
101
|
+
output: {
|
|
102
|
+
filename: isProduction ? '[name].min.js' : '[name].js',
|
|
103
|
+
chunkFilename: isProduction ? '[name].min.js?v=[chunkhash]' : '[name].js?v=[chunkhash]',
|
|
104
|
+
pathinfo: false,
|
|
105
|
+
clean: isProduction,
|
|
192
106
|
},
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Resolve Configuration
|
|
110
|
+
*
|
|
111
|
+
* @see https://webpack.js.org/configuration/resolve/
|
|
112
|
+
*/
|
|
113
|
+
resolve: {
|
|
114
|
+
extensions: ['.js', '.json'],
|
|
197
115
|
},
|
|
198
116
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Optimization Configuration
|
|
119
|
+
* @see https://webpack.js.org/configuration/optimization/
|
|
120
|
+
*/
|
|
121
|
+
optimization: {
|
|
122
|
+
minimize: isProduction,
|
|
123
|
+
minimizer: [
|
|
124
|
+
isProduction ? new CssMinimizerPlugin({test: /\.min\.css$/}) : false
|
|
125
|
+
].filter(Boolean),
|
|
205
126
|
},
|
|
206
127
|
|
|
207
128
|
// This option determine how different types of module within the project will be treated.
|
|
208
129
|
// @see https://webpack.js.org/configuration/module/
|
|
209
130
|
module:{
|
|
210
|
-
...baseConfig.module,
|
|
211
131
|
// This option sets up loaders for webpack configuration.
|
|
212
132
|
// Loaders allow webpack to process various types because by default webpack only
|
|
213
133
|
// understand JavaScript and JSON files.
|
|
214
134
|
// @see https://webpack.js.org/concepts/#loaders
|
|
215
135
|
rules: [
|
|
216
|
-
...baseConfig.module.rules,
|
|
217
136
|
/**
|
|
218
137
|
* Default template loader for html is lodash,
|
|
219
|
-
* lets switch to handlebars
|
|
138
|
+
* lets switch to handlebars-loader
|
|
139
|
+
* @see https://github.com/pcardune/handlebars-loader
|
|
220
140
|
*/
|
|
221
141
|
{
|
|
222
|
-
test: /\.html$/,
|
|
142
|
+
test: /\.(html|handlebars|hbs)$/,
|
|
223
143
|
loader: 'handlebars-loader',
|
|
224
|
-
options:
|
|
225
|
-
rootRelative: process.cwd(),
|
|
226
|
-
helperDirs: [
|
|
227
|
-
path.resolve(currentPath, 'helpers', 'bootstrap'),
|
|
228
|
-
path.resolve(currentPath, 'helpers', 'logic'),
|
|
229
|
-
path.resolve(currentPath, 'helpers', 'object'),
|
|
230
|
-
path.resolve(currentPath, 'helpers', 'string')
|
|
231
|
-
].concat( customTemplateHelpers ),
|
|
232
|
-
partialResolver: function(partial, callback){
|
|
233
|
-
/**
|
|
234
|
-
* All template partials are loaded from the root directory
|
|
235
|
-
* if the file doesn't exist we fallback to our template partials
|
|
236
|
-
*/
|
|
237
|
-
let fallbackPath = path.join( currentPath, '..', 'template' );
|
|
238
|
-
let partialDir = '';
|
|
239
|
-
|
|
240
|
-
// template parameter specific partials
|
|
241
|
-
switch( partial ){
|
|
242
|
-
/**
|
|
243
|
-
* Semantic elements are served from the /semantic/ directory
|
|
244
|
-
*
|
|
245
|
-
* - header
|
|
246
|
-
* - footer
|
|
247
|
-
*
|
|
248
|
-
* @link https://www.w3schools.com/html/html5_semantic_elements.asp
|
|
249
|
-
*/
|
|
250
|
-
case 'branding':
|
|
251
|
-
case 'footer':
|
|
252
|
-
case 'header':
|
|
253
|
-
case 'mobileControls':
|
|
254
|
-
case 'navFooter':
|
|
255
|
-
case 'navHeader':
|
|
256
|
-
case 'utilityHeader':
|
|
257
|
-
partialDir = 'semantics';
|
|
258
|
-
break;
|
|
259
|
-
|
|
260
|
-
// content is served from the /content/ directory
|
|
261
|
-
case 'index':
|
|
262
|
-
case 'content':
|
|
263
|
-
partialDir = 'content';
|
|
264
|
-
break;
|
|
265
|
-
|
|
266
|
-
// components are served from the /components/ directory
|
|
267
|
-
case 'alert':
|
|
268
|
-
case 'card':
|
|
269
|
-
partialDir = `components/${partial}`;
|
|
270
|
-
break;
|
|
271
|
-
|
|
272
|
-
// forms are served from the /forms/ directory
|
|
273
|
-
case 'searchForm':
|
|
274
|
-
partialDir = 'forms';
|
|
275
|
-
break;
|
|
276
|
-
|
|
277
|
-
// tables are served from the /tables/ directory
|
|
278
|
-
case partial.includes('Table'):
|
|
279
|
-
partialDir = 'tables';
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if( partialDir ){
|
|
284
|
-
// we remove the Form from the name
|
|
285
|
-
// we remove the Table from the name
|
|
286
|
-
// we change the partial name from camelCase to dash-case
|
|
287
|
-
partial = partial.replace(/(Form|Table)/, '').replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
288
|
-
|
|
289
|
-
partial = fs.existsSync( path.join( appPath, partialDir, `/${partial}.html` )) ?
|
|
290
|
-
path.join( appPath, partialDir, `/${partial}.html` ) :
|
|
291
|
-
path.join( fallbackPath, partialDir, `/${partial}.html` )
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
callback(false, partial );
|
|
295
|
-
}
|
|
296
|
-
}
|
|
144
|
+
options: handlebarsLoaderOptions
|
|
297
145
|
},
|
|
298
146
|
// Handle `.tsx` and `.ts` files.
|
|
299
147
|
{
|
|
@@ -311,6 +159,43 @@ let webpackConfig = {
|
|
|
311
159
|
}
|
|
312
160
|
]
|
|
313
161
|
},
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Devtool Configuration
|
|
165
|
+
* WordPress by default uses 'source-map' for devtool which affects build and rebuild speed.
|
|
166
|
+
* For development we switch to 'eval' which is much faster.
|
|
167
|
+
* For production we turn off devtool completely.
|
|
168
|
+
* @see https://webpack.js.org/configuration/devtool/#devtool
|
|
169
|
+
*/
|
|
170
|
+
devtool: isProduction ? 'source-map' : 'eval',
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Turn off caching of generated modules and chunks.
|
|
174
|
+
* @see https://webpack.js.org/configuration/cache/
|
|
175
|
+
*/
|
|
176
|
+
cache: false,
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Stats Configuration
|
|
180
|
+
* @see https://webpack.js.org/configuration/stats/
|
|
181
|
+
*/
|
|
182
|
+
stats: {
|
|
183
|
+
errors: false,
|
|
184
|
+
errorDetails: false,
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Performance Configuration
|
|
190
|
+
* Throw hints when asset size exceeds the specified limit for production.
|
|
191
|
+
*
|
|
192
|
+
* @see https://webpack.js.org/configuration/performance/
|
|
193
|
+
*/
|
|
194
|
+
performance: {
|
|
195
|
+
maxAssetSize: 350000,
|
|
196
|
+
maxEntrypointSize: 500000,
|
|
197
|
+
hints: isProduction ? 'warning' : false,
|
|
198
|
+
},
|
|
314
199
|
|
|
315
200
|
// WordPress already enqueues scripts and makes them available
|
|
316
201
|
// in global scope so those scripts don't need to be included on the bundle. For webpack
|
|
@@ -329,190 +214,29 @@ let webpackConfig = {
|
|
|
329
214
|
'@wordpress/hooks': ['vendor', 'wp', 'hooks'],
|
|
330
215
|
'@wordpress/i18n': ['vendor', 'wp', 'i18n'],
|
|
331
216
|
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Serve Only
|
|
337
|
-
*/
|
|
338
|
-
if( 'serve' === webpackCommand ){
|
|
339
|
-
let template = flags.includes('--template') ? getArgVal('--template') : 'default';
|
|
340
|
-
let scheme = flags.includes('--scheme') ? getArgVal('--scheme') : 'oceanside';
|
|
341
|
-
|
|
342
|
-
let host = flags.includes('--host') ? getArgVal('--host') : 'localhost';
|
|
343
|
-
let port = flags.includes('--port') ? getArgVal('--port') : 9000;
|
|
344
|
-
let server = flags.includes('--server-type') ? getArgVal('--server-type') : 'http';
|
|
217
|
+
},
|
|
345
218
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
writeToDisk: true,
|
|
350
|
-
},
|
|
351
|
-
hot: true,
|
|
352
|
-
compress: true,
|
|
353
|
-
allowedHosts: 'auto',
|
|
354
|
-
server,
|
|
355
|
-
host,
|
|
356
|
-
port,
|
|
357
|
-
open: [ `${server}://${host}:${port}` ],
|
|
358
|
-
static: [
|
|
359
|
-
/**
|
|
360
|
-
* Static files are served from the following files in the following order
|
|
361
|
-
* we don't have to add the build directory since that is the output.path and proxied
|
|
362
|
-
*
|
|
363
|
-
* node_modules - Allows loading files from other npm packages
|
|
364
|
-
*/
|
|
365
|
-
{
|
|
366
|
-
directory: path.join(appPath, 'node_modules'),
|
|
367
|
-
},
|
|
368
|
-
/**
|
|
369
|
-
* Static files are served from the following files in the following order
|
|
370
|
-
* we don't have to add the build directory since that is the output.path and proxied
|
|
371
|
-
*
|
|
372
|
-
* node_modules - Allows loading files from other npm packages
|
|
373
|
-
*/
|
|
374
|
-
{
|
|
375
|
-
directory: path.join(appPath, 'media'),
|
|
376
|
-
}
|
|
377
|
-
],
|
|
378
|
-
proxy:[
|
|
379
|
-
/**
|
|
380
|
-
* WordPress Proxy Configuration is deprecated
|
|
381
|
-
* @since 28.2.0
|
|
382
|
-
*/
|
|
383
|
-
{
|
|
384
|
-
context: ['/build'],
|
|
385
|
-
target: `${server}://${host}:${port}`,
|
|
386
|
-
pathRewrite: {
|
|
387
|
-
'^/build': ''
|
|
388
|
-
},
|
|
389
|
-
logLevel: 'info'
|
|
390
|
-
},
|
|
391
|
-
/**
|
|
392
|
-
* We proxy the node_modules and src so they serve from the root
|
|
393
|
-
*/
|
|
394
|
-
{
|
|
395
|
-
context: ['/node_modules'],
|
|
396
|
-
target: `${server}://${host}:${port}`,
|
|
397
|
-
pathRewrite: { '^/node_modules': '' },
|
|
398
|
-
},
|
|
399
|
-
/**
|
|
400
|
-
* We proxy the node_modules and src so they serve from the root
|
|
401
|
-
*/
|
|
402
|
-
{
|
|
403
|
-
context: ['/media'],
|
|
404
|
-
target: `${server}://${host}:${port}`,
|
|
405
|
-
pathRewrite: { '^/media': '' },
|
|
406
|
-
}
|
|
407
|
-
]
|
|
408
|
-
}
|
|
219
|
+
plugins: [
|
|
220
|
+
// we remove empty scripts
|
|
221
|
+
new RemoveEmptyScriptsPlugin(),
|
|
409
222
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
new CAWebHTMLPlugin({
|
|
413
|
-
template,
|
|
414
|
-
templateParameters: {
|
|
415
|
-
scheme: 'false' !== scheme ? scheme : false
|
|
416
|
-
},
|
|
223
|
+
// certain files can be skipped when serving
|
|
224
|
+
new HtmlWebpackSkipAssetsPlugin({
|
|
417
225
|
skipAssets: [
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
226
|
+
/.*-rtl.css/, // we skip the Right-to-Left Styles
|
|
227
|
+
/css-audit.*/, // we skip the CSSAudit Files
|
|
228
|
+
/a11y.*/, // we skip the A11y Files
|
|
229
|
+
/jshint.*/, // we skip the JSHint Files
|
|
230
|
+
]
|
|
423
231
|
}),
|
|
424
|
-
|
|
425
|
-
new HtmlWebpackLinkTypePlugin(),
|
|
426
|
-
! flagExists('--no-jshint') ? new JSHintPlugin() : false,
|
|
427
|
-
! flagExists('--no-audit') ? new CSSAuditPlugin() : false,
|
|
428
|
-
! flagExists('--no-a11y') ? new A11yPlugin() : false
|
|
429
|
-
)
|
|
430
|
-
|
|
431
|
-
// we add the SERP (Search Engine Results Page)
|
|
432
|
-
// if the caweb.json has a google search id
|
|
433
|
-
if( cawebJson.site?.google?.search ){
|
|
434
|
-
webpackConfig.plugins.push(
|
|
435
|
-
new CAWebHTMLPlugin({
|
|
436
|
-
template: 'search',
|
|
437
|
-
templateParameters: {
|
|
438
|
-
scheme: 'false' !== scheme ? scheme : false
|
|
439
|
-
},
|
|
440
|
-
filename: 'serp.html',
|
|
441
|
-
title: 'Search Results Page',
|
|
442
|
-
skipAssets: [
|
|
443
|
-
/.*-rtl.css/, // we skip the Right-to-Left Styles
|
|
444
|
-
/css-audit.*/, // we skip the CSSAudit Files
|
|
445
|
-
/a11y.*/, // we skip the A11y Files
|
|
446
|
-
/jshint.*/, // we skip the JSHint Files
|
|
447
|
-
]
|
|
448
|
-
})
|
|
449
|
-
)
|
|
450
|
-
}
|
|
232
|
+
],
|
|
451
233
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
.filter( Dirent => Dirent.isFile() && Dirent.name.endsWith('.html') )
|
|
460
|
-
.map( Dirent => {
|
|
461
|
-
let fileTemplate = path.join(Dirent.parentPath, Dirent.name);
|
|
462
|
-
let p = fs.readFileSync( fileTemplate ).toString();
|
|
463
|
-
let fileName = fileTemplate.replace(basePageDir, '');
|
|
464
|
-
|
|
465
|
-
webpackConfig.plugins.push(
|
|
466
|
-
new CAWebHTMLPlugin({
|
|
467
|
-
template,
|
|
468
|
-
filename: fileName,
|
|
469
|
-
// replace .html, forward slashes with a space, uppercase the first letter of each word, remove Index
|
|
470
|
-
// this is to make sure the title is readable
|
|
471
|
-
// and not just a file name
|
|
472
|
-
title: fileName.replace(/\.html$/, '').replace(/[\/\\]/g, ' ').replace(/\b\w/g, c => c.toUpperCase()).replace(' Index', ''),
|
|
473
|
-
templateParameters: {
|
|
474
|
-
bodyHtmlSnippet: p,
|
|
475
|
-
},
|
|
476
|
-
skipAssets: [
|
|
477
|
-
/.*-rtl.css/, // we skip the Right-to-Left Styles
|
|
478
|
-
/css-audit.*/, // we skip the CSSAudit Files
|
|
479
|
-
/a11y.*/, // we skip the A11y Files
|
|
480
|
-
/jshint.*/, // we skip the JSHint Files
|
|
481
|
-
]
|
|
482
|
-
})
|
|
483
|
-
)
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Production only
|
|
490
|
-
*/
|
|
491
|
-
if( mode === 'production' ){
|
|
492
|
-
// Config
|
|
493
|
-
webpackConfig.name = 'compressed';
|
|
494
|
-
webpackConfig.devtool = false;
|
|
495
|
-
|
|
496
|
-
// Output
|
|
497
|
-
webpackConfig.output.filename = '[name].min.js';
|
|
498
|
-
webpackConfig.output.chunkFilename = '[name].min.js?v=[chunkhash]';
|
|
499
|
-
|
|
500
|
-
// Plugins
|
|
501
|
-
webpackConfig.plugins.push(
|
|
502
|
-
new MiniCSSExtractPlugin( { filename: '[name].min.css' } ),
|
|
503
|
-
new RtlCssPlugin( { filename: '[name]-rtl.min.css' } )
|
|
504
|
-
)
|
|
505
|
-
|
|
506
|
-
// Optimization
|
|
507
|
-
webpackConfig.optimization.minimize = true;
|
|
508
|
-
webpackConfig.optimization.minimizer.push(
|
|
509
|
-
new CssMinimizerPlugin({test: /\.min\.css$/})
|
|
510
|
-
)
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// we remove empty scripts
|
|
514
|
-
webpackConfig.plugins.push(
|
|
515
|
-
new RemoveEmptyScriptsPlugin()
|
|
516
|
-
);
|
|
234
|
+
/**
|
|
235
|
+
* DevServer is only added during 'serve' command
|
|
236
|
+
*
|
|
237
|
+
* @see https://webpack.js.org/configuration/dev-server/
|
|
238
|
+
*/
|
|
239
|
+
devServer
|
|
240
|
+
};
|
|
517
241
|
|
|
518
|
-
export default webpackConfig;
|
|
242
|
+
export default merge( baseConfig, webpackConfig );
|