@atomicsmash/compiler 0.7.4 → 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,425 +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: [
69
- {
70
- test: /\.vue$/,
71
- loader: "vue-loader",
72
- },
73
- ],
74
- plugin: [new vueLoaderModule.VueLoaderPlugin()],
75
- }))
76
- .catch(() => ({ loader: [], plugin: [] }));
77
- const postCSSConfig = [
78
- [
79
- // Support tailwind if package is found
80
- ...tailwindPostCSSPlugin,
81
- postCSSPresetEnv({
82
- // Support all CSS that is considered stable.
83
- stage: 2,
84
- features: {
85
- // Polyfill support for custom media queries
86
- "custom-media-queries": true,
87
- },
88
- }),
89
- ],
90
- ...(MODE === "production" ? [cssNano] : []),
91
- ];
92
- function getEsBuildLoaderSetup(loader) {
93
- return {
94
- use: {
95
- loader: "esbuild-loader",
96
- options: {
97
- loader: loader,
98
- // Set target to match the browserslist config
99
- target: browserslistToEsbuild(),
100
- tsconfig: process.cwd() + "/tsconfig.json",
101
- },
102
- },
103
- exclude: (file) => {
104
- // Exclude all block.json.ts files (handled by a separate loader).
105
- if (argv.experimentalBlocksSupport && file.includes("block.json")) {
106
- return true;
107
- }
108
- // Exclude node_modules files from transpilation unless they are vue files and the vue-loader is present
109
- if (vueConfig.loader.length > 0) {
110
- return file.includes("node_modules") && !file.includes(".vue.js");
111
- }
112
- return file.includes("node_modules");
113
- },
114
- };
115
- }
116
- const compiler = webpack({
117
- resolveLoader: {
118
- modules: [
119
- // Get modules from project node_modules folder
120
- "node_modules",
121
- // Get modules from this package's internal node modules folder once installed
122
- resolvePath(import.meta.dirname, "../", "node_modules"),
123
- ],
124
- },
125
- // Add sourcemaps in dev mode
126
- devtool: MODE === "development" ? "source-map" : false,
127
- // Set the environment mode from NODE_ENV.
128
- mode: MODE,
129
- entry: await glob([
130
- ...(argv.experimentalBlocksSupport
131
- ? [`${srcFolder}/blocks/**/block.json.ts`]
132
- : []),
133
- // Parse all direct children of the JS folder, as long as they are JS & TS files
134
- `${srcFolder}/scripts/*.{js,ts,jsx,tsx}`,
135
- // Parse all direct children of the CSS folder, as long as they are CSS files
136
- `${srcFolder}/styles/*.css`,
137
- // Parse all nested children of the CSS folder, as long as they are non-partial SCSS files
138
- `${srcFolder}/styles/**/[^_]*.s[ac]ss`,
139
- ], {
140
- ignore: argv.experimentalBlocksSupport
141
- ? argv.excludeBlocks.map((blockName) => `${srcFolder}/blocks/**/${blockName}/block.json.ts`)
142
- : [],
143
- }).then(async (paths) => {
144
- const { restOfPaths, entryPoints } = argv.experimentalBlocksSupport
145
- ? await getBlocksAssetsEntryPoints(paths, {}, srcFolder)
146
- : { restOfPaths: paths, entryPoints: {} };
147
- restOfPaths.forEach((path) => {
148
- const entryName = path.replace(srcFolder, "");
149
- entryPoints[entryName] = {
150
- import: path,
151
- // Output filenames with content hash for fingerprinting
152
- filename: `${path.replace(`${srcFolder}${pathSeparator}`, "").replace(extname(path), "").replace("scripts/", "js/")}${MODE === "production" ? `.[contenthash]` : ""}.js`,
153
- };
154
- });
155
- return entryPoints;
156
- }),
157
- output: {
158
- // Output filenames with content hash for fingerprinting
159
- filename: "js/[name].[contenthash].js",
160
- // Clear files between runs
161
- clean: true,
162
- library: {
163
- // Output JS files with Universal Module Definition
164
- type: "umd",
165
- },
166
- // Set the output folder
167
- path: distFolder,
168
- },
169
- resolve: {
170
- // support TSConfig paths as aliases
171
- plugins: [
172
- new TsconfigPathsPlugin({
173
- configFile: process.cwd() + "/tsconfig.json",
174
- }),
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) => relative(srcFolder, pathData.filename ?? "")
216
- .replace(".scss", ".[contenthash].css")
217
- .replace("styles/", "css/"),
218
- },
219
- use: [
220
- {
221
- loader: "postcss-loader",
222
- options: {
223
- postcssOptions: {
224
- sourceMap: MODE === "development",
225
- plugins: postCSSConfig,
226
- },
227
- },
228
- },
229
- {
230
- loader: "sass-loader",
231
- options: {
232
- sourceMap: MODE === "development",
233
- },
234
- },
235
- ],
236
- },
237
- // Run the css files through postcss
238
- {
239
- test: /\.css$/i,
240
- type: "asset/resource",
241
- generator: {
242
- binary: false,
243
- filename: (pathData) => relative(srcFolder, pathData.filename ?? "")
244
- .replace(".css", ".[contenthash].css")
245
- .replace("styles/", "css/"),
246
- },
247
- use: [
248
- {
249
- loader: "postcss-loader",
250
- options: {
251
- postcssOptions: {
252
- sourceMap: MODE === "development",
253
- plugins: postCSSConfig,
254
- },
255
- },
256
- },
257
- ],
258
- },
259
- ],
260
- },
261
- plugins: [
262
- // Output progress information when compiling
263
- new webpack.ProgressPlugin(),
264
- // Generate a manifest file of assets to make it possible to target fingerprinted files
265
- new WebpackAssetsManifest({
266
- writeToDisk: true,
267
- output: `${distFolder}/assets-manifest.json`,
268
- customize(entry) {
269
- if (!entry || !entry.key || typeof entry.key === "number") {
270
- return entry;
271
- }
272
- if (entry.key === "assets.php" ||
273
- entry.key === "wordpress-assets-info.php" ||
274
- entry.key.startsWith("fonts") ||
275
- entry.key.startsWith("images")) {
276
- return false;
277
- }
278
- if (entry.key === "spritemap.svg") {
279
- return { key: "icons/sprite.svg", value: entry.value };
280
- }
281
- if (entry.key.startsWith("/")) {
282
- entry.key = entry.key.slice(1);
283
- }
284
- if (entry.key.startsWith("css/")) {
285
- entry.key = entry.key.replace("css/", "styles/");
286
- }
287
- if (entry.key.endsWith(".js.js")) {
288
- entry.key = entry.key.slice(0, -3);
289
- }
290
- return entry;
291
- },
292
- }),
293
- // Create an SVG sprite from a folder of provided icons
294
- new SVGSpritemapPlugin(`${srcFolder}/icons/*.svg`, {
295
- output: {
296
- filename: "icons/sprite.[contenthash].svg",
297
- },
298
- sprite: {
299
- prefix: "",
300
- generate: {
301
- title: false,
302
- },
303
- },
304
- }),
305
- // Copy fonts and images from the src folder to assets (available for backwards compatibility, not recommended)
306
- new CopyPlugin({
307
- patterns: [
308
- {
309
- from: "**/*",
310
- context: resolvePath(srcFolder, "fonts"),
311
- to({ context, absoluteFilename }) {
312
- return `fonts/${relative(context, absoluteFilename ?? "")}`;
313
- },
314
- noErrorOnMissing: true,
315
- },
316
- {
317
- from: "**/*",
318
- context: resolvePath(srcFolder, "images"),
319
- to({ context, absoluteFilename }) {
320
- return `images/${relative(context, absoluteFilename ?? "")}`;
321
- },
322
- noErrorOnMissing: true,
323
- },
324
- ],
325
- }),
326
- // Output a bundle analysis if flag was provided
327
- ...(argv.analyse ? [new BundleAnalyzerPlugin({})] : []),
328
- // Extract wordpress dependencies from js files and output a wordpress assets file for enqueues
329
- new DependencyExtractionWebpackPlugin({
330
- combineAssets: true,
331
- // Blocks plugin converts this to php, but it must be output as json here.
332
- ...(argv.experimentalBlocksSupport
333
- ? {
334
- outputFormat: "json",
335
- combinedOutputFile: "wordpress-assets-info.json",
336
- }
337
- : {
338
- outputFormat: "php",
339
- combinedOutputFile: "wordpress-assets-info.php",
340
- }),
341
- }),
342
- // Support Vue files if vue-loader is present
343
- ...vueConfig.plugin,
344
- ...(argv.experimentalBlocksSupport ? [new BlocksPlugin(srcFolder)] : []),
345
- ],
346
- optimization: {
347
- minimizer: [
348
- // Minify JS files
349
- new EsbuildPlugin({
350
- target: browserslistToEsbuild(),
351
- }),
352
- ],
353
- },
354
- });
355
- if (argv.watch) {
356
- const watching = compiler.watch({
357
- // Example
358
- aggregateTimeout: 300,
359
- poll: undefined,
360
- }, (error, stats) => {
361
- if (error) {
362
- console.error(error.stack ?? error);
363
- process.exitCode = 1;
364
- watching.close((closeError) => {
365
- console.error(closeError);
366
- });
367
- }
368
- else if (stats) {
369
- const info = stats.toJson();
370
- if (stats.hasErrors()) {
371
- const errors = info.errors;
372
- console.warn("The compiler produced the following errors: \n");
373
- for (const error of errors) {
374
- console.warn(error.message);
375
- }
376
- }
377
- if (stats.hasWarnings()) {
378
- const warnings = info.warnings;
379
- console.warn("The compiler produced the following warnings: \n");
380
- for (const warning of warnings) {
381
- console.warn(warning.message);
382
- }
383
- }
384
- }
385
- });
386
- process.on("SIGINT", function () {
387
- watching.close((closeError) => {
388
- console.error(closeError);
389
- });
390
- });
391
- }
392
- else {
393
- compiler.run((error, stats) => {
394
- if (error) {
395
- console.error(error);
396
- process.exitCode = 1;
397
- }
398
- else if (stats) {
399
- const info = stats.toJson();
400
- if (stats.hasErrors()) {
401
- const errors = info.errors;
402
- console.warn("The compiler produced the following errors: \n");
403
- for (const error of errors) {
404
- console.warn(error.message);
405
- }
406
- process.exitCode = 1;
407
- }
408
- if (stats.hasWarnings()) {
409
- const warnings = info.warnings;
410
- console.warn("The compiler produced the following warnings: \n");
411
- for (const warning of warnings) {
412
- console.warn(warning.message);
413
- }
414
- if (!stats.hasErrors()) {
415
- process.exitCode = 2;
416
- }
417
- }
418
- }
419
- compiler.close((closeError) => {
420
- if (closeError) {
421
- process.exitCode = 1;
422
- }
423
- });
424
- });
425
- }
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.4",
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",