@atomicsmash/compiler 0.7.5 → 0.8.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/dist/cli.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ declare global {
3
+ namespace NodeJS {
4
+ interface ProcessEnv {
5
+ NODE_ENV: "production" | "development" | "test" | undefined;
6
+ }
7
+ }
8
+ }
9
+ export {};
10
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAQA,OAAO,CAAC,MAAM,CAAC;IAEd,UAAU,MAAM,CAAC;QAEhB,UAAU,UAAU;YACnB,QAAQ,EAAE,YAAY,GAAG,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;SAC5D;KACD;CACD"}
package/dist/cli.js ADDED
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ import { cosmiconfig } from "cosmiconfig";
3
+ import webpack from "webpack";
4
+ import yargs from "yargs";
5
+ import { hideBin } from "yargs/helpers";
6
+ import { config as defaultConfig } from "./config";
7
+ const argv = await yargs(hideBin(process.argv))
8
+ .options({
9
+ in: {
10
+ demandOption: true,
11
+ describe: "The directory where the source files can be found. Relative to cwd.",
12
+ type: "string",
13
+ },
14
+ out: {
15
+ demandOption: true,
16
+ describe: "The directory where the compiled files will out output. Relative to cwd.",
17
+ type: "string",
18
+ },
19
+ watch: {
20
+ boolean: true,
21
+ default: false,
22
+ describe: "Whether to watch the files in the source folder for changes and compile.",
23
+ },
24
+ analyse: {
25
+ boolean: true,
26
+ default: false,
27
+ describe: "See a report of the generated bundle once built.",
28
+ },
29
+ experimentalBlocksSupport: {
30
+ boolean: true,
31
+ default: false,
32
+ describe: "Enable experimental support for WordPress blocks compilation.",
33
+ },
34
+ excludeBlocks: {
35
+ array: true,
36
+ string: true,
37
+ default: ["__TEMPLATE__"],
38
+ describe: "A comma separated list of the folder names of blocks to exclude from compilation. Requires experimental blocks support.",
39
+ },
40
+ })
41
+ .showHelpOnFail(false, "Specify --help for available options")
42
+ .parse();
43
+ const explorer = cosmiconfig("smash-compiler");
44
+ const config = await explorer.search().then(async (config) => {
45
+ if (!config) {
46
+ return await defaultConfig({ ...argv });
47
+ }
48
+ return config.config;
49
+ });
50
+ const compiler = webpack(config);
51
+ if (argv.watch) {
52
+ const watching = compiler.watch({
53
+ // Example
54
+ aggregateTimeout: 300,
55
+ poll: undefined,
56
+ }, (error, stats) => {
57
+ if (error) {
58
+ console.error(error.stack ?? error);
59
+ process.exitCode = 1;
60
+ watching.close((closeError) => {
61
+ console.error(closeError);
62
+ });
63
+ }
64
+ else if (stats) {
65
+ const info = stats.toJson();
66
+ if (stats.hasErrors()) {
67
+ const errors = info.errors;
68
+ console.warn("The compiler produced the following errors: \n");
69
+ for (const error of errors) {
70
+ console.warn(error.message);
71
+ }
72
+ }
73
+ if (stats.hasWarnings()) {
74
+ const warnings = info.warnings;
75
+ console.warn("The compiler produced the following warnings: \n");
76
+ for (const warning of warnings) {
77
+ console.warn(warning.message);
78
+ }
79
+ }
80
+ }
81
+ });
82
+ process.on("SIGINT", function () {
83
+ watching.close((closeError) => {
84
+ console.error(closeError);
85
+ });
86
+ });
87
+ }
88
+ else {
89
+ compiler.run((error, stats) => {
90
+ if (error) {
91
+ console.error(error);
92
+ process.exitCode = 1;
93
+ }
94
+ else if (stats) {
95
+ const info = stats.toJson();
96
+ if (stats.hasErrors()) {
97
+ const errors = info.errors;
98
+ console.warn("The compiler produced the following errors: \n");
99
+ for (const error of errors) {
100
+ console.warn(error.message);
101
+ }
102
+ process.exitCode = 1;
103
+ }
104
+ if (stats.hasWarnings()) {
105
+ const warnings = info.warnings;
106
+ console.warn("The compiler produced the following warnings: \n");
107
+ for (const warning of warnings) {
108
+ console.warn(warning.message);
109
+ }
110
+ if (!stats.hasErrors()) {
111
+ process.exitCode = 2;
112
+ }
113
+ }
114
+ }
115
+ compiler.close((closeError) => {
116
+ if (closeError) {
117
+ process.exitCode = 1;
118
+ }
119
+ });
120
+ });
121
+ }
@@ -0,0 +1,122 @@
1
+ import type { PathData } from "webpack";
2
+ import DependencyExtractionWebpackPlugin from "@wordpress/dependency-extraction-webpack-plugin";
3
+ import CopyPlugin from "copy-webpack-plugin";
4
+ import cssNano from "cssnano";
5
+ import { EsbuildPlugin } from "esbuild-loader";
6
+ import SVGSpritemapPlugin from "svg-spritemap-webpack-plugin";
7
+ import { TsconfigPathsPlugin } from "tsconfig-paths-webpack-plugin";
8
+ import webpack from "webpack";
9
+ import { WebpackAssetsManifest } from "webpack-assets-manifest";
10
+ import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
11
+ import { BlocksPlugin } from "./BlocksPlugin.js";
12
+ export declare function config(options: {
13
+ /**
14
+ * The directory where the source files can be found. Relative to cwd.
15
+ */
16
+ in: string;
17
+ /**
18
+ * The directory where the compiled files will out output. Relative to cwd.
19
+ */
20
+ out: string;
21
+ /**
22
+ * Whether to watch the files in the source folder for changes and compile.
23
+ */
24
+ watch?: boolean | undefined;
25
+ /**
26
+ * See a report of the generated bundle once built.
27
+ */
28
+ analyse?: boolean | undefined;
29
+ /**
30
+ * Enable experimental support for WordPress blocks compilation.
31
+ */
32
+ experimentalBlocksSupport?: boolean | undefined;
33
+ /**
34
+ * A comma separated list of the folder names of blocks to exclude from compilation. Requires experimental blocks support.
35
+ */
36
+ excludeBlocks?: string[] | undefined;
37
+ }): Promise<{
38
+ resolveLoader: {
39
+ modules: string[];
40
+ };
41
+ devtool: false | "source-map";
42
+ mode: "production" | "development";
43
+ entry: string | string[] | (() => string | webpack.EntryObject | string[] | Promise<string | string[] | webpack.EntryObject>) | webpack.EntryObject | undefined;
44
+ output: {
45
+ filename: string;
46
+ clean: true;
47
+ library: {
48
+ type: string;
49
+ };
50
+ path: string;
51
+ };
52
+ resolve: {
53
+ alias: {
54
+ vue?: string | undefined;
55
+ };
56
+ plugins: TsconfigPathsPlugin[];
57
+ extensions: string[];
58
+ };
59
+ module: {
60
+ rules: ({
61
+ test: RegExp;
62
+ loader: string;
63
+ } | {
64
+ use: {
65
+ loader: string;
66
+ options: {
67
+ loader: "ts" | "default";
68
+ target: string[];
69
+ tsconfig: string;
70
+ };
71
+ };
72
+ exclude: (file: string) => boolean;
73
+ test: RegExp;
74
+ resourceQuery: (value: string) => boolean;
75
+ type?: undefined;
76
+ generator?: undefined;
77
+ } | {
78
+ test: RegExp;
79
+ type: string;
80
+ generator: {
81
+ filename: (pathData: PathData) => string;
82
+ binary?: undefined;
83
+ };
84
+ use: {
85
+ loader: string;
86
+ };
87
+ } | {
88
+ test: RegExp;
89
+ type: string;
90
+ generator: {
91
+ binary: boolean;
92
+ filename: (pathData: PathData) => string | undefined;
93
+ };
94
+ use: ({
95
+ loader: string;
96
+ options: {
97
+ postcssOptions: {
98
+ sourceMap: boolean;
99
+ plugins: ((import("postcss").Processor | import("postcss").PluginCreator<{
100
+ base?: string;
101
+ optimize?: boolean | {
102
+ minify?: boolean;
103
+ };
104
+ }> | typeof import("tailwindcss").default | import("postcss").Plugin)[] | typeof cssNano)[];
105
+ };
106
+ sourceMap?: undefined;
107
+ };
108
+ } | {
109
+ loader: string;
110
+ options: {
111
+ sourceMap: boolean;
112
+ postcssOptions?: undefined;
113
+ };
114
+ })[];
115
+ })[];
116
+ };
117
+ plugins: (import("vue-loader").VueLoaderPlugin | webpack.ProgressPlugin | WebpackAssetsManifest | SVGSpritemapPlugin | CopyPlugin | BundleAnalyzerPlugin | DependencyExtractionWebpackPlugin | BlocksPlugin | webpack.DefinePlugin)[];
118
+ optimization: {
119
+ minimizer: EsbuildPlugin[];
120
+ };
121
+ }>;
122
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,QAAQ,EAAe,MAAM,SAAS,CAAC;AAOpE,OAAO,iCAAiC,MAAM,iDAAiD,CAAC;AAEhG,OAAO,UAAU,MAAM,qBAAqB,CAAC;AAC7C,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C,OAAO,kBAAkB,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIjD,wBAAsB,MAAM,CAAC,OAAO,EAAE;IACrC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B;;OAEG;IACH,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChD;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qCA6K6B,QAAQ;;;;;;;;;;;qCAeX,QAAQ;;;;;;;;;;sCAxOrB,CAAC;;;;;;;;;;;;;;;;;;;GAkad"}
package/dist/config.js ADDED
@@ -0,0 +1,363 @@
1
+ import { sep as pathSeparator, extname, resolve as resolvePath, relative, } from "node:path";
2
+ import DependencyExtractionWebpackPlugin from "@wordpress/dependency-extraction-webpack-plugin";
3
+ import browserslistToEsbuild from "browserslist-to-esbuild";
4
+ import CopyPlugin from "copy-webpack-plugin";
5
+ import cssNano from "cssnano";
6
+ import { EsbuildPlugin } from "esbuild-loader";
7
+ import glob from "fast-glob";
8
+ import postCSSPresetEnv from "postcss-preset-env";
9
+ import SVGSpritemapPlugin from "svg-spritemap-webpack-plugin";
10
+ import { TsconfigPathsPlugin } from "tsconfig-paths-webpack-plugin";
11
+ import webpack from "webpack";
12
+ import { WebpackAssetsManifest } from "webpack-assets-manifest";
13
+ import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
14
+ import { BlocksPlugin } from "./BlocksPlugin.js";
15
+ import { getBlocksAssetsEntryPoints } from "./getBlocksAssetsEntryPoints.js";
16
+ // ArgumentsCamelCase<Awaited<ReturnType<typeof builder>["argv"]>>
17
+ export async function config(options) {
18
+ const argv = {
19
+ watch: false,
20
+ analyse: false,
21
+ experimentalBlocksSupport: false,
22
+ excludeBlocks: ["__TEMPLATE__"],
23
+ ...options,
24
+ };
25
+ const MODE = process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test"
26
+ ? "development"
27
+ : "production";
28
+ const srcFolder = resolvePath(argv.in);
29
+ const distFolder = resolvePath(argv.out);
30
+ // Add optional support for Tailwind if tailwind postcss plugin is installed
31
+ const tailwindPostCSSPlugin = await import("@tailwindcss/postcss")
32
+ .then((tailwindPostCSS) => [tailwindPostCSS.default])
33
+ .catch(async () => await import("tailwindcss")
34
+ .then((tailwindcss) => [tailwindcss.default])
35
+ .catch(() => []));
36
+ // Add optional support for Vue if vue-loader is installed
37
+ const vueConfig = await import("vue-loader")
38
+ .then((vueLoaderModule) => ({
39
+ loader: [{ test: /\.vue$/, loader: "vue-loader" }],
40
+ plugin: [new vueLoaderModule.VueLoaderPlugin()],
41
+ globals: {
42
+ __VUE_OPTIONS_API__: "true",
43
+ __VUE_PROD_DEVTOOLS__: "false",
44
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false",
45
+ },
46
+ aliases: { vue: "vue/dist/vue.esm-bundler.js" },
47
+ }))
48
+ .catch(() => ({ loader: [], plugin: [], globals: {}, aliases: {} }));
49
+ const postCSSConfig = [
50
+ [
51
+ // Support tailwind if package is found
52
+ ...tailwindPostCSSPlugin,
53
+ postCSSPresetEnv({
54
+ // Support all CSS that is considered stable.
55
+ stage: 2,
56
+ features: {
57
+ // Polyfill support for custom media queries
58
+ "custom-media-queries": true,
59
+ },
60
+ }),
61
+ ],
62
+ ...(MODE === "production" ? [cssNano] : []),
63
+ ];
64
+ function getEsBuildLoaderSetup(loader) {
65
+ return {
66
+ use: {
67
+ loader: "esbuild-loader",
68
+ options: {
69
+ loader: loader,
70
+ // Set target to match the browserslist config
71
+ target: browserslistToEsbuild(),
72
+ tsconfig: process.cwd() + "/tsconfig.json",
73
+ },
74
+ },
75
+ exclude: (file) => {
76
+ // Exclude all block.json.ts files (handled by a separate loader).
77
+ if (argv.experimentalBlocksSupport && file.includes("block.json")) {
78
+ return true;
79
+ }
80
+ // Exclude node_modules files from transpilation unless they are vue files and the vue-loader is present
81
+ if (vueConfig.loader.length > 0) {
82
+ return file.includes("node_modules") && !file.includes(".vue.js");
83
+ }
84
+ return file.includes("node_modules");
85
+ },
86
+ };
87
+ }
88
+ return {
89
+ resolveLoader: {
90
+ modules: [
91
+ // Get modules from project node_modules folder
92
+ "node_modules",
93
+ // Get modules from this package's internal node modules folder once installed
94
+ resolvePath(import.meta.dirname, "../", "node_modules"),
95
+ ],
96
+ },
97
+ // Add sourcemaps in dev mode
98
+ devtool: MODE === "development" ? "source-map" : false,
99
+ // Set the environment mode from NODE_ENV.
100
+ mode: MODE,
101
+ entry: await glob([
102
+ ...(argv.experimentalBlocksSupport
103
+ ? [`${srcFolder}/blocks/**/block.json.ts`]
104
+ : []),
105
+ // Parse all direct children of the JS folder, as long as they are JS & TS files
106
+ `${srcFolder}/scripts/*.{js,ts,jsx,tsx}`,
107
+ // Parse all direct children of the CSS folder, as long as they are CSS files
108
+ `${srcFolder}/styles/*.css`,
109
+ // Parse all nested children of the CSS folder, as long as they are non-partial SCSS files
110
+ `${srcFolder}/styles/**/[^_]*.s[ac]ss`,
111
+ ], {
112
+ ignore: argv.experimentalBlocksSupport
113
+ ? argv.excludeBlocks.map((blockName) => `${srcFolder}/blocks/**/${blockName}/block.json.ts`)
114
+ : [],
115
+ }).then(async (paths) => {
116
+ const { restOfPaths, entryPoints } = argv.experimentalBlocksSupport
117
+ ? await getBlocksAssetsEntryPoints(paths, {}, srcFolder)
118
+ : { restOfPaths: paths, entryPoints: {} };
119
+ restOfPaths.forEach((path) => {
120
+ const entryName = path.replace(srcFolder, "");
121
+ entryPoints[entryName] = {
122
+ import: path,
123
+ // Output filenames with content hash for fingerprinting
124
+ filename: `${path.replace(`${srcFolder}${pathSeparator}`, "").replace(extname(path), "").replace("scripts/", "js/")}${MODE === "production" ? `.[contenthash]` : ""}.js`,
125
+ };
126
+ });
127
+ return entryPoints;
128
+ }),
129
+ output: {
130
+ // Output filenames with content hash for fingerprinting
131
+ filename: "js/[name].[contenthash].js",
132
+ // Clear files between runs
133
+ clean: true,
134
+ library: {
135
+ // Output JS files with Universal Module Definition
136
+ type: "umd",
137
+ },
138
+ // Set the output folder
139
+ path: distFolder,
140
+ },
141
+ resolve: {
142
+ alias: { ...vueConfig.aliases },
143
+ // support TSConfig paths as aliases
144
+ plugins: [
145
+ new TsconfigPathsPlugin({
146
+ configFile: process.cwd() + "/tsconfig.json",
147
+ }),
148
+ ],
149
+ // resolve TS extensions
150
+ extensions: [".tsx", ".ts", ".js", ".jsx", ".vue"],
151
+ },
152
+ module: {
153
+ rules: [
154
+ // Support Vue files if vue-loader is present
155
+ ...vueConfig.loader,
156
+ // Use ESBuild loader to transpile JS & TS files
157
+ {
158
+ test: /\.[jt]sx?$/,
159
+ resourceQuery: (value) => value.includes("vue"),
160
+ // Vue files require explicitly informing ESBuild of the type of loader to use.
161
+ ...getEsBuildLoaderSetup("ts"),
162
+ },
163
+ {
164
+ test: /\.[jt]sx?$/,
165
+ resourceQuery: (value) => !value.includes("vue"),
166
+ ...getEsBuildLoaderSetup("default"),
167
+ },
168
+ ...(argv.experimentalBlocksSupport
169
+ ? [
170
+ {
171
+ test: /block\.json\.ts$/,
172
+ type: "asset/resource",
173
+ generator: {
174
+ filename: (pathData) => relative(srcFolder, pathData.filename ?? "").slice(0, -3),
175
+ },
176
+ use: {
177
+ loader: resolvePath(import.meta.dirname, "./BlocksLoader.js"),
178
+ },
179
+ },
180
+ ]
181
+ : []),
182
+ // Transpile SCSS files and run the result through postcss
183
+ {
184
+ test: /\.s[ac]ss$/i,
185
+ type: "asset/resource",
186
+ generator: {
187
+ binary: false,
188
+ filename: (pathData) => {
189
+ const fileName = pathData.filename;
190
+ if (!fileName) {
191
+ return;
192
+ }
193
+ const isVendorFile = fileName.includes("node_modules");
194
+ if (isVendorFile) {
195
+ const vendorPathData = fileName.split(pathSeparator);
196
+ const nodeModulesPosition = vendorPathData.findIndex((value) => value.includes("node_modules"));
197
+ const vendorArray = vendorPathData.slice(nodeModulesPosition + 1, nodeModulesPosition + 3);
198
+ let vendor;
199
+ if (vendorArray[0]?.startsWith("@")) {
200
+ vendor = vendorArray.join(pathSeparator);
201
+ }
202
+ else {
203
+ vendor = vendorArray[0] ?? "";
204
+ }
205
+ return ["css", "vendor", vendor, vendorPathData.at(-1)]
206
+ .join(pathSeparator)
207
+ .replace(".scss", ".[contenthash].css");
208
+ }
209
+ return relative(srcFolder, pathData.filename ?? "")
210
+ .replace(".scss", ".[contenthash].css")
211
+ .replace("styles/", "css/");
212
+ },
213
+ },
214
+ use: [
215
+ {
216
+ loader: "postcss-loader",
217
+ options: {
218
+ postcssOptions: {
219
+ sourceMap: MODE === "development",
220
+ plugins: postCSSConfig,
221
+ },
222
+ },
223
+ },
224
+ {
225
+ loader: "sass-loader",
226
+ options: { sourceMap: MODE === "development" },
227
+ },
228
+ ],
229
+ },
230
+ // Run the css files through postcss
231
+ {
232
+ test: /\.css$/i,
233
+ type: "asset/resource",
234
+ generator: {
235
+ binary: false,
236
+ filename: (pathData) => {
237
+ const fileName = pathData.filename;
238
+ if (!fileName) {
239
+ return;
240
+ }
241
+ const isVendorFile = fileName.includes("node_modules");
242
+ if (isVendorFile) {
243
+ const vendorPathData = fileName.split(pathSeparator);
244
+ const nodeModulesPosition = vendorPathData.findIndex((value) => value.includes("node_modules"));
245
+ const vendorArray = vendorPathData.slice(nodeModulesPosition + 1, nodeModulesPosition + 3);
246
+ let vendor;
247
+ if (vendorArray[0]?.startsWith("@")) {
248
+ vendor = vendorArray.join(pathSeparator);
249
+ }
250
+ else {
251
+ vendor = vendorArray[0] ?? "";
252
+ }
253
+ return ["css", "vendor", vendor, vendorPathData.at(-1)]
254
+ .join(pathSeparator)
255
+ .replace(".css", ".[contenthash].css");
256
+ }
257
+ return relative(srcFolder, pathData.filename ?? "")
258
+ .replace(".css", ".[contenthash].css")
259
+ .replace("styles/", "css/");
260
+ },
261
+ },
262
+ use: [
263
+ {
264
+ loader: "postcss-loader",
265
+ options: {
266
+ postcssOptions: {
267
+ sourceMap: MODE === "development",
268
+ plugins: postCSSConfig,
269
+ },
270
+ },
271
+ },
272
+ ],
273
+ },
274
+ ],
275
+ },
276
+ plugins: [
277
+ // Output progress information when compiling
278
+ new webpack.ProgressPlugin(),
279
+ // Generate a manifest file of assets to make it possible to target fingerprinted files
280
+ new WebpackAssetsManifest({
281
+ writeToDisk: true,
282
+ output: `${distFolder}/assets-manifest.json`,
283
+ customize(entry) {
284
+ if (!entry || !entry.key || typeof entry.key === "number") {
285
+ return entry;
286
+ }
287
+ if (entry.key === "assets.php" ||
288
+ entry.key === "wordpress-assets-info.php" ||
289
+ entry.key.endsWith(".map") ||
290
+ entry.key.startsWith("fonts") ||
291
+ entry.key.startsWith("images")) {
292
+ return false;
293
+ }
294
+ if (entry.key === "spritemap.svg") {
295
+ return { key: "icons/sprite.svg", value: entry.value };
296
+ }
297
+ if (entry.key.startsWith("/")) {
298
+ entry.key = entry.key.slice(1);
299
+ }
300
+ if (entry.key.startsWith("css/")) {
301
+ entry.key = entry.key.replace("css/", "styles/");
302
+ }
303
+ if (entry.key.endsWith(".js.js")) {
304
+ entry.key = entry.key.slice(0, -3);
305
+ }
306
+ return entry;
307
+ },
308
+ }),
309
+ // Create an SVG sprite from a folder of provided icons
310
+ new SVGSpritemapPlugin(`${srcFolder}/icons/*.svg`, {
311
+ output: { filename: "icons/sprite.[contenthash].svg" },
312
+ sprite: { prefix: "", generate: { title: false } },
313
+ }),
314
+ // Copy fonts and images from the src folder to assets (available for backwards compatibility, not recommended)
315
+ new CopyPlugin({
316
+ patterns: [
317
+ {
318
+ from: "**/*",
319
+ context: resolvePath(srcFolder, "fonts"),
320
+ to({ context, absoluteFilename }) {
321
+ return `fonts/${relative(context, absoluteFilename ?? "")}`;
322
+ },
323
+ noErrorOnMissing: true,
324
+ },
325
+ {
326
+ from: "**/*",
327
+ context: resolvePath(srcFolder, "images"),
328
+ to({ context, absoluteFilename }) {
329
+ return `images/${relative(context, absoluteFilename ?? "")}`;
330
+ },
331
+ noErrorOnMissing: true,
332
+ },
333
+ ],
334
+ }),
335
+ // Output a bundle analysis if flag was provided
336
+ ...(argv.analyse ? [new BundleAnalyzerPlugin({})] : []),
337
+ // Extract wordpress dependencies from js files and output a wordpress assets file for enqueues
338
+ new DependencyExtractionWebpackPlugin({
339
+ combineAssets: true,
340
+ // Blocks plugin converts this to php, but it must be output as json here.
341
+ ...(argv.experimentalBlocksSupport
342
+ ? {
343
+ outputFormat: "json",
344
+ combinedOutputFile: "wordpress-assets-info.json",
345
+ }
346
+ : {
347
+ outputFormat: "php",
348
+ combinedOutputFile: "wordpress-assets-info.php",
349
+ }),
350
+ }),
351
+ // Support Vue files if vue-loader is present
352
+ ...vueConfig.plugin,
353
+ ...(argv.experimentalBlocksSupport ? [new BlocksPlugin(srcFolder)] : []),
354
+ new webpack.DefinePlugin({ ...vueConfig.globals }),
355
+ ],
356
+ optimization: {
357
+ minimizer: [
358
+ // Minify JS files
359
+ new EsbuildPlugin({ target: browserslistToEsbuild() }),
360
+ ],
361
+ },
362
+ };
363
+ }
package/dist/index.d.ts CHANGED
@@ -1,10 +1,3 @@
1
- #!/usr/bin/env node
2
- declare global {
3
- namespace NodeJS {
4
- interface ProcessEnv {
5
- NODE_ENV: "production" | "development" | "test" | undefined;
6
- }
7
- }
8
- }
9
- export {};
1
+ export { config } from "./config";
2
+ export { config as default } from "./config";
10
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAyBA,OAAO,CAAC,MAAM,CAAC;IAEd,UAAU,MAAM,CAAC;QAEhB,UAAU,UAAU;YACnB,QAAQ,EAAE,YAAY,GAAG,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;SAC5D;KACD;CACD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,460 +1,2 @@
1
- #!/usr/bin/env node
2
- import { sep as pathSeparator, extname, resolve as resolvePath, relative, } from "node:path";
3
- import DependencyExtractionWebpackPlugin from "@wordpress/dependency-extraction-webpack-plugin";
4
- import browserslistToEsbuild from "browserslist-to-esbuild";
5
- import CopyPlugin from "copy-webpack-plugin";
6
- import cssNano from "cssnano";
7
- import { EsbuildPlugin } from "esbuild-loader";
8
- import glob from "fast-glob";
9
- import postCSSPresetEnv from "postcss-preset-env";
10
- import SVGSpritemapPlugin from "svg-spritemap-webpack-plugin";
11
- import { TsconfigPathsPlugin } from "tsconfig-paths-webpack-plugin";
12
- import webpack from "webpack";
13
- import { WebpackAssetsManifest } from "webpack-assets-manifest";
14
- import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
15
- import yargs from "yargs";
16
- import { hideBin } from "yargs/helpers";
17
- import { BlocksPlugin } from "./BlocksPlugin.js";
18
- import { getBlocksAssetsEntryPoints } from "./getBlocksAssetsEntryPoints.js";
19
- const argv = await yargs(hideBin(process.argv))
20
- .options({
21
- in: {
22
- demandOption: true,
23
- describe: "The directory where the source files can be found. Relative to cwd.",
24
- type: "string",
25
- },
26
- out: {
27
- demandOption: true,
28
- describe: "The directory where the compiled files will out output. Relative to cwd.",
29
- type: "string",
30
- },
31
- watch: {
32
- boolean: true,
33
- default: false,
34
- describe: "Whether to watch the files in the source folder for changes and compile.",
35
- },
36
- analyse: {
37
- boolean: true,
38
- default: false,
39
- describe: "See a report of the generated bundle once built.",
40
- },
41
- experimentalBlocksSupport: {
42
- boolean: true,
43
- default: false,
44
- describe: "Enable experimental support for WordPress blocks compilation.",
45
- },
46
- excludeBlocks: {
47
- array: true,
48
- default: ["__TEMPLATE__"],
49
- describe: "A comma separated list of the folder names of blocks to exclude from compilation. Requires experimental blocks support.",
50
- },
51
- })
52
- .showHelpOnFail(false, "Specify --help for available options")
53
- .parse();
54
- const MODE = process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test"
55
- ? "development"
56
- : "production";
57
- const srcFolder = resolvePath(argv.in);
58
- const distFolder = resolvePath(argv.out);
59
- // Add optional support for Tailwind if tailwind postcss plugin is installed
60
- const tailwindPostCSSPlugin = await import("@tailwindcss/postcss")
61
- .then((tailwindPostCSS) => [tailwindPostCSS.default])
62
- .catch(async () => await import("tailwindcss")
63
- .then((tailwindcss) => [tailwindcss.default])
64
- .catch(() => []));
65
- // Add optional support for Vue if vue-loader is installed
66
- const vueConfig = await import("vue-loader")
67
- .then((vueLoaderModule) => ({
68
- loader: [{ test: /\.vue$/, loader: "vue-loader" }],
69
- plugin: [new vueLoaderModule.VueLoaderPlugin()],
70
- globals: {
71
- __VUE_OPTIONS_API__: "true",
72
- __VUE_PROD_DEVTOOLS__: "false",
73
- __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false",
74
- },
75
- aliases: { vue: "vue/dist/vue.esm-bundler.js" },
76
- }))
77
- .catch(() => ({ loader: [], plugin: [], globals: {}, aliases: {} }));
78
- const postCSSConfig = [
79
- [
80
- // Support tailwind if package is found
81
- ...tailwindPostCSSPlugin,
82
- postCSSPresetEnv({
83
- // Support all CSS that is considered stable.
84
- stage: 2,
85
- features: {
86
- // Polyfill support for custom media queries
87
- "custom-media-queries": true,
88
- },
89
- }),
90
- ],
91
- ...(MODE === "production" ? [cssNano] : []),
92
- ];
93
- function getEsBuildLoaderSetup(loader) {
94
- return {
95
- use: {
96
- loader: "esbuild-loader",
97
- options: {
98
- loader: loader,
99
- // Set target to match the browserslist config
100
- target: browserslistToEsbuild(),
101
- tsconfig: process.cwd() + "/tsconfig.json",
102
- },
103
- },
104
- exclude: (file) => {
105
- // Exclude all block.json.ts files (handled by a separate loader).
106
- if (argv.experimentalBlocksSupport && file.includes("block.json")) {
107
- return true;
108
- }
109
- // Exclude node_modules files from transpilation unless they are vue files and the vue-loader is present
110
- if (vueConfig.loader.length > 0) {
111
- return file.includes("node_modules") && !file.includes(".vue.js");
112
- }
113
- return file.includes("node_modules");
114
- },
115
- };
116
- }
117
- const compiler = webpack({
118
- resolveLoader: {
119
- modules: [
120
- // Get modules from project node_modules folder
121
- "node_modules",
122
- // Get modules from this package's internal node modules folder once installed
123
- resolvePath(import.meta.dirname, "../", "node_modules"),
124
- ],
125
- },
126
- // Add sourcemaps in dev mode
127
- devtool: MODE === "development" ? "source-map" : false,
128
- // Set the environment mode from NODE_ENV.
129
- mode: MODE,
130
- entry: await glob([
131
- ...(argv.experimentalBlocksSupport
132
- ? [`${srcFolder}/blocks/**/block.json.ts`]
133
- : []),
134
- // Parse all direct children of the JS folder, as long as they are JS & TS files
135
- `${srcFolder}/scripts/*.{js,ts,jsx,tsx}`,
136
- // Parse all direct children of the CSS folder, as long as they are CSS files
137
- `${srcFolder}/styles/*.css`,
138
- // Parse all nested children of the CSS folder, as long as they are non-partial SCSS files
139
- `${srcFolder}/styles/**/[^_]*.s[ac]ss`,
140
- ], {
141
- ignore: argv.experimentalBlocksSupport
142
- ? argv.excludeBlocks.map((blockName) => `${srcFolder}/blocks/**/${blockName}/block.json.ts`)
143
- : [],
144
- }).then(async (paths) => {
145
- const { restOfPaths, entryPoints } = argv.experimentalBlocksSupport
146
- ? await getBlocksAssetsEntryPoints(paths, {}, srcFolder)
147
- : { restOfPaths: paths, entryPoints: {} };
148
- restOfPaths.forEach((path) => {
149
- const entryName = path.replace(srcFolder, "");
150
- entryPoints[entryName] = {
151
- import: path,
152
- // Output filenames with content hash for fingerprinting
153
- filename: `${path.replace(`${srcFolder}${pathSeparator}`, "").replace(extname(path), "").replace("scripts/", "js/")}${MODE === "production" ? `.[contenthash]` : ""}.js`,
154
- };
155
- });
156
- return entryPoints;
157
- }),
158
- output: {
159
- // Output filenames with content hash for fingerprinting
160
- filename: "js/[name].[contenthash].js",
161
- // Clear files between runs
162
- clean: true,
163
- library: {
164
- // Output JS files with Universal Module Definition
165
- type: "umd",
166
- },
167
- // Set the output folder
168
- path: distFolder,
169
- },
170
- resolve: {
171
- alias: { ...vueConfig.aliases },
172
- // support TSConfig paths as aliases
173
- plugins: [
174
- new TsconfigPathsPlugin({ configFile: process.cwd() + "/tsconfig.json" }),
175
- ],
176
- // resolve TS extensions
177
- extensions: [".tsx", ".ts", ".js", ".jsx", ".vue"],
178
- },
179
- module: {
180
- rules: [
181
- // Support Vue files if vue-loader is present
182
- ...vueConfig.loader,
183
- // Use ESBuild loader to transpile JS & TS files
184
- {
185
- test: /\.[jt]sx?$/,
186
- resourceQuery: (value) => value.includes("vue"),
187
- // Vue files require explicitly informing ESBuild of the type of loader to use.
188
- ...getEsBuildLoaderSetup("ts"),
189
- },
190
- {
191
- test: /\.[jt]sx?$/,
192
- resourceQuery: (value) => !value.includes("vue"),
193
- ...getEsBuildLoaderSetup("default"),
194
- },
195
- ...(argv.experimentalBlocksSupport
196
- ? [
197
- {
198
- test: /block\.json\.ts$/,
199
- type: "asset/resource",
200
- generator: {
201
- filename: (pathData) => relative(srcFolder, pathData.filename ?? "").slice(0, -3),
202
- },
203
- use: {
204
- loader: resolvePath(import.meta.dirname, "./BlocksLoader.js"),
205
- },
206
- },
207
- ]
208
- : []),
209
- // Transpile SCSS files and run the result through postcss
210
- {
211
- test: /\.s[ac]ss$/i,
212
- type: "asset/resource",
213
- generator: {
214
- binary: false,
215
- filename: (pathData) => {
216
- const fileName = pathData.filename;
217
- if (!fileName) {
218
- return;
219
- }
220
- const isVendorFile = fileName.includes("node_modules");
221
- if (isVendorFile) {
222
- const vendorPathData = fileName.split(pathSeparator);
223
- const nodeModulesPosition = vendorPathData.findIndex((value) => value.includes("node_modules"));
224
- const vendorArray = vendorPathData.slice(nodeModulesPosition + 1, nodeModulesPosition + 3);
225
- let vendor;
226
- if (vendorArray[0]?.startsWith("@")) {
227
- vendor = vendorArray.join(pathSeparator);
228
- }
229
- else {
230
- vendor = vendorArray[0] ?? "";
231
- }
232
- return ["css", "vendor", vendor, vendorPathData.at(-1)]
233
- .join(pathSeparator)
234
- .replace(".scss", ".[contenthash].css");
235
- }
236
- return relative(srcFolder, pathData.filename ?? "")
237
- .replace(".scss", ".[contenthash].css")
238
- .replace("styles/", "css/");
239
- },
240
- },
241
- use: [
242
- {
243
- loader: "postcss-loader",
244
- options: {
245
- postcssOptions: {
246
- sourceMap: MODE === "development",
247
- plugins: postCSSConfig,
248
- },
249
- },
250
- },
251
- {
252
- loader: "sass-loader",
253
- options: { sourceMap: MODE === "development" },
254
- },
255
- ],
256
- },
257
- // Run the css files through postcss
258
- {
259
- test: /\.css$/i,
260
- type: "asset/resource",
261
- generator: {
262
- binary: false,
263
- filename: (pathData) => {
264
- const fileName = pathData.filename;
265
- if (!fileName) {
266
- return;
267
- }
268
- const isVendorFile = fileName.includes("node_modules");
269
- if (isVendorFile) {
270
- const vendorPathData = fileName.split(pathSeparator);
271
- const nodeModulesPosition = vendorPathData.findIndex((value) => value.includes("node_modules"));
272
- const vendorArray = vendorPathData.slice(nodeModulesPosition + 1, nodeModulesPosition + 3);
273
- let vendor;
274
- if (vendorArray[0]?.startsWith("@")) {
275
- vendor = vendorArray.join(pathSeparator);
276
- }
277
- else {
278
- vendor = vendorArray[0] ?? "";
279
- }
280
- return ["css", "vendor", vendor, vendorPathData.at(-1)]
281
- .join(pathSeparator)
282
- .replace(".css", ".[contenthash].css");
283
- }
284
- return relative(srcFolder, pathData.filename ?? "")
285
- .replace(".css", ".[contenthash].css")
286
- .replace("styles/", "css/");
287
- },
288
- },
289
- use: [
290
- {
291
- loader: "postcss-loader",
292
- options: {
293
- postcssOptions: {
294
- sourceMap: MODE === "development",
295
- plugins: postCSSConfig,
296
- },
297
- },
298
- },
299
- ],
300
- },
301
- ],
302
- },
303
- plugins: [
304
- // Output progress information when compiling
305
- new webpack.ProgressPlugin(),
306
- // Generate a manifest file of assets to make it possible to target fingerprinted files
307
- new WebpackAssetsManifest({
308
- writeToDisk: true,
309
- output: `${distFolder}/assets-manifest.json`,
310
- customize(entry) {
311
- if (!entry || !entry.key || typeof entry.key === "number") {
312
- return entry;
313
- }
314
- if (entry.key === "assets.php" ||
315
- entry.key === "wordpress-assets-info.php" ||
316
- entry.key.endsWith(".map") ||
317
- entry.key.startsWith("fonts") ||
318
- entry.key.startsWith("images")) {
319
- return false;
320
- }
321
- if (entry.key === "spritemap.svg") {
322
- return { key: "icons/sprite.svg", value: entry.value };
323
- }
324
- if (entry.key.startsWith("/")) {
325
- entry.key = entry.key.slice(1);
326
- }
327
- if (entry.key.startsWith("css/")) {
328
- entry.key = entry.key.replace("css/", "styles/");
329
- }
330
- if (entry.key.endsWith(".js.js")) {
331
- entry.key = entry.key.slice(0, -3);
332
- }
333
- return entry;
334
- },
335
- }),
336
- // Create an SVG sprite from a folder of provided icons
337
- new SVGSpritemapPlugin(`${srcFolder}/icons/*.svg`, {
338
- output: { filename: "icons/sprite.[contenthash].svg" },
339
- sprite: { prefix: "", generate: { title: false } },
340
- }),
341
- // Copy fonts and images from the src folder to assets (available for backwards compatibility, not recommended)
342
- new CopyPlugin({
343
- patterns: [
344
- {
345
- from: "**/*",
346
- context: resolvePath(srcFolder, "fonts"),
347
- to({ context, absoluteFilename }) {
348
- return `fonts/${relative(context, absoluteFilename ?? "")}`;
349
- },
350
- noErrorOnMissing: true,
351
- },
352
- {
353
- from: "**/*",
354
- context: resolvePath(srcFolder, "images"),
355
- to({ context, absoluteFilename }) {
356
- return `images/${relative(context, absoluteFilename ?? "")}`;
357
- },
358
- noErrorOnMissing: true,
359
- },
360
- ],
361
- }),
362
- // Output a bundle analysis if flag was provided
363
- ...(argv.analyse ? [new BundleAnalyzerPlugin({})] : []),
364
- // Extract wordpress dependencies from js files and output a wordpress assets file for enqueues
365
- new DependencyExtractionWebpackPlugin({
366
- combineAssets: true,
367
- // Blocks plugin converts this to php, but it must be output as json here.
368
- ...(argv.experimentalBlocksSupport
369
- ? {
370
- outputFormat: "json",
371
- combinedOutputFile: "wordpress-assets-info.json",
372
- }
373
- : {
374
- outputFormat: "php",
375
- combinedOutputFile: "wordpress-assets-info.php",
376
- }),
377
- }),
378
- // Support Vue files if vue-loader is present
379
- ...vueConfig.plugin,
380
- ...(argv.experimentalBlocksSupport ? [new BlocksPlugin(srcFolder)] : []),
381
- new webpack.DefinePlugin({ ...vueConfig.globals }),
382
- ],
383
- optimization: {
384
- minimizer: [
385
- // Minify JS files
386
- new EsbuildPlugin({ target: browserslistToEsbuild() }),
387
- ],
388
- },
389
- });
390
- if (argv.watch) {
391
- const watching = compiler.watch({
392
- // Example
393
- aggregateTimeout: 300,
394
- poll: undefined,
395
- }, (error, stats) => {
396
- if (error) {
397
- console.error(error.stack ?? error);
398
- process.exitCode = 1;
399
- watching.close((closeError) => {
400
- console.error(closeError);
401
- });
402
- }
403
- else if (stats) {
404
- const info = stats.toJson();
405
- if (stats.hasErrors()) {
406
- const errors = info.errors;
407
- console.warn("The compiler produced the following errors: \n");
408
- for (const error of errors) {
409
- console.warn(error.message);
410
- }
411
- }
412
- if (stats.hasWarnings()) {
413
- const warnings = info.warnings;
414
- console.warn("The compiler produced the following warnings: \n");
415
- for (const warning of warnings) {
416
- console.warn(warning.message);
417
- }
418
- }
419
- }
420
- });
421
- process.on("SIGINT", function () {
422
- watching.close((closeError) => {
423
- console.error(closeError);
424
- });
425
- });
426
- }
427
- else {
428
- compiler.run((error, stats) => {
429
- if (error) {
430
- console.error(error);
431
- process.exitCode = 1;
432
- }
433
- else if (stats) {
434
- const info = stats.toJson();
435
- if (stats.hasErrors()) {
436
- const errors = info.errors;
437
- console.warn("The compiler produced the following errors: \n");
438
- for (const error of errors) {
439
- console.warn(error.message);
440
- }
441
- process.exitCode = 1;
442
- }
443
- if (stats.hasWarnings()) {
444
- const warnings = info.warnings;
445
- console.warn("The compiler produced the following warnings: \n");
446
- for (const warning of warnings) {
447
- console.warn(warning.message);
448
- }
449
- if (!stats.hasErrors()) {
450
- process.exitCode = 2;
451
- }
452
- }
453
- }
454
- compiler.close((closeError) => {
455
- if (closeError) {
456
- process.exitCode = 1;
457
- }
458
- });
459
- });
460
- }
1
+ export { config } from "./config";
2
+ export { config as default } from "./config";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atomicsmash/compiler",
3
3
  "type": "module",
4
- "version": "0.7.5",
4
+ "version": "0.8.0",
5
5
  "description": "A universal compiler for all Atomic Smash projects.",
6
6
  "keywords": [
7
7
  "cli",
@@ -25,7 +25,7 @@
25
25
  ],
26
26
  "main": "index",
27
27
  "bin": {
28
- "smash-compile": "./dist/index.js"
28
+ "smash-compile": "./dist/cli.js"
29
29
  },
30
30
  "types": "index",
31
31
  "publishConfig": {
@@ -47,6 +47,7 @@
47
47
  "@wordpress/dependency-extraction-webpack-plugin": "^6.15.0",
48
48
  "browserslist-to-esbuild": "^2.1.1",
49
49
  "copy-webpack-plugin": "^12.0.2",
50
+ "cosmiconfig": "^9.0.0",
50
51
  "cssnano": "^7.0.6",
51
52
  "esbuild-loader": "^4.3.0",
52
53
  "fast-glob": "^3.3.2",