diff --git a/DOCS.md b/DOCS.md index 7a88528..5a7252f 100644 --- a/DOCS.md +++ b/DOCS.md @@ -19,16 +19,16 @@ $ weldable -h ``` #### Options -| CLI OPTION | DESCRIPTION | CHOICES | DEFAULT | -|----------------|--------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|--------------| -| -e, --env | Use a default configuration type if NODE_ENV is not set to the available choices of "development" and "production" | development, production | production | -| -l, --lang | Codebase language, JS or TS | js, ts | js | -| -s, --stats | Output JSON webpack bundle stats for use with "webpack-bundle-analyzer". Use the default or enter a relative path and filename | | ./stats.json | -| --tsconfig | Generate a base tsconfig from one of the available NPM @tsconfig/[base]. An existing tsconfig.json will override this option, see "tsconfig-opt" | create-react-app, node18, node20, react-native, recommended, strictest | | -| --tsconfig-opt | Regenerate or merge a tsconfig. Useful if a tsconfig already exists | merge, regen | regen | -| -x, --extend | Extend, or override, the default configs with your own relative path webpack configs using webpack merge. | | | -| -h, --help | | | | -| -v, --version | | | | +| CLI OPTION | DESCRIPTION | CHOICES | DEFAULT | +|----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|--------------| +| -e, --env | Use a default configuration type if NODE_ENV is not set to the available choices of "development" and "production" | development, production | production | +| -l, --loader | Preprocess loader, use the classic JS (babel-loader), TS (ts-loader), or "none" to use webpack defaults, or a different loader. | js, ts, none | js | +| -s, --stats | Output JSON webpack bundle stats for use with "webpack-bundle-analyzer". Use the default or enter a relative path and filename | | ./stats.json | +| --tsconfig | Generate a base tsconfig from one of the available NPM @tsconfig/[base]. An existing tsconfig.json will override this option, see "tsconfig-opt". This option can be run without running webpack. | create-react-app, node18, node20, react-native, recommended, strictest | | +| --tsconfig-opt | Regenerate or merge a tsconfig. Useful if a tsconfig already exists. Requires the use of "tsconfig" option | merge, regen | regen | +| -x, --extend | Extend, or override, the default configs with your own relative path webpack configs using webpack merge. | | | +| -h, --help | | | | +| -v, --version | | | | #### NPM script use CLI usage can be placed under NPM scripts diff --git a/README.md b/README.md index 4700e21..db5e5a1 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,17 @@ Default webpack development and production configuration. -The goal of `weldable` was to make it easier to install `webpack` build packages and be up and running with a basic -`development` or `production` server with minimal preferences. +The goal of `weldable` is to make it easier to install `webpack` build packages and be up and running with a basic +`development` or `production` build with minimal preferences. `weldable` is intended... -- To be used for basic webpack development and production builds. +- To be quickly used for basic webpack development and production builds. - To purposefully not include webpack configurations for linting and styling aspects beyond basic webpack capabilities. - To be designed with the expectation that you can expand on the `weldable` base using the CLI extend option. `-x ./webpack.exampleConfig.js`. -- To be used as a build resource with exposed webpack plugins/addons. And without the need to reinstall available webpack packages (or at least the ones `weldable` uses). +- To be used as a single build resource with exposed webpack plugins/addons. And without the need to reinstall available webpack packages (or at least the ones `weldable` uses). + +[If weldable doesn't work for you, you can always go back to the `webpack` project `init` command](https://webpack.js.org/configuration/#set-up-a-new-webpack-project) ## Requirements The basic requirements: @@ -50,11 +52,12 @@ For in-depth use of `weldable` see our [DOCS](./DOCS.md). Options: -e, --env Use a default configuration type if NODE_ENV is not set to the available choices. [string] [choices: "development", "production"] [default: "production"] - -l, --lang Codebase language, JS or TS [string] [choices: "js", "ts"] [default: "js"] + -l, --loader Preprocess loader, use the classic JS (babel-loader), TS (ts-loader), or "none" to use webpack defaults, or a + different loader. [string] [choices: "none", "js", "ts"] [default: "js"] -s, --stats Output JSON webpack bundle stats. Use the default, or a relative project path and filename [./stats.json] [string] --tsconfig Generate a base tsconfig from NPM @tsconfig/[base]. An existing tsconfig.json will override this option, see - tsconfig-opt. + tsconfig-opt. This option can be run without running webpack. [string] [choices: "", "create-react-app", "node18", "node20", "react-native", "recommended", "strictest"] --tsconfig-opt Regenerate or merge a tsconfig [string] [choices: "merge", "regen"] [default: "regen"] -x, --extend Extend, or override, the default configs with your own relative path webpack configs using webpack merge.[array] diff --git a/bin/cli.js b/bin/cli.js index b11a135..4e08e3a 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -12,7 +12,7 @@ const { setupDotenvFilesForEnv } = require('../src/dotenv'); const { env: nodeEnv, extend: extendedConfigs, - lang: language, + loader, stats: statsFile, tsconfig: baseTsConfig, 'tsconfig-opt': tsConfigOptions @@ -31,10 +31,11 @@ const { default: 'production' }) .option('l', { - alias: 'lang', - describe: 'Codebase language, JS or TS', + alias: 'loader', + describe: + 'Preprocess loader, use the classic JS (babel-loader), TS (ts-loader), or "none" to use webpack defaults, or a different loader.', type: 'string', - choices: ['js', 'ts'], + choices: ['none', 'js', 'ts'], default: 'js' }) .option('s', { @@ -46,7 +47,7 @@ const { }) .option('tsconfig', { describe: - 'Generate a base tsconfig from NPM @tsconfig/[base]. An existing tsconfig.json will override this option, see tsconfig-opt.', + 'Generate a base tsconfig from NPM @tsconfig/[base]. An existing tsconfig.json will override this option, see tsconfig-opt. This option can be run without running webpack.', type: 'string', choices: ['', 'create-react-app', 'node18', 'node20', 'react-native', 'recommended', 'strictest'] }) @@ -54,7 +55,8 @@ const { describe: 'Regenerate or merge a tsconfig', type: 'string', choices: ['merge', 'regen'], - default: 'regen' + implies: 'tsconfig', + coerce: args => (!args && 'regen') || args }) .option('x', { alias: 'extend', @@ -68,9 +70,9 @@ const { /** * Set global OPTIONS * - * @type {{statsFile: string, dotenv: object, isRegenTsConfig: boolean, baseTsConfig: string, - * extendedConfigs: Array, isMergeTsConfig: boolean, language: string, statsPath: string, - * nodeEnv: string}} + * @type {{statsFile: string, dotenv: object, isRegenTsConfig: boolean, isCreateTsConfig: boolean, + * loader: string, isCreateTsConfigOnly: boolean, baseTsConfig: string, extendedConfigs: Array, + * isMergeTsConfig: boolean, statsPath: string, nodeEnv: string}} * @private */ OPTIONS._set = { @@ -88,13 +90,21 @@ OPTIONS._set = { return setupDotenvFilesForEnv({ env: process.env.NODE_ENV, relativePath: this.contextPath, isMessaging: true }); }, + isCreateTsConfig: function () { + const isBaseTsConfig = typeof baseTsConfig === 'string'; + return (loader === 'ts' && isBaseTsConfig) || isBaseTsConfig; + }, + isCreateTsConfigOnly: function () { + const isBaseTsConfig = typeof baseTsConfig === 'string'; + return (loader !== 'ts' && isBaseTsConfig) || false; + }, isMergeTsConfig: function () { return tsConfigOptions === 'merge'; }, isRegenTsConfig: function () { return tsConfigOptions === 'regen'; }, - language, + loader, statsFile: function () { return (statsFile && path.basename(statsFile)) || undefined; }, diff --git a/cspell.config.json b/cspell.config.json index 35cfa05..2819603 100644 --- a/cspell.config.json +++ b/cspell.config.json @@ -7,6 +7,7 @@ "fnames", "nocolor", "oneline", + "preprocess", "regen", "stringifier", "systemvars" diff --git a/src/README.md b/src/README.md index ee5832b..c330b70 100644 --- a/src/README.md +++ b/src/README.md @@ -237,10 +237,24 @@ Start `weldable` -### Init~weldable() ⇒ Promise.<void> +### Init~weldable(options) ⇒ Promise.<void> Organize package functionality. **Kind**: inner method of [Init](#module_Init) + + + + + + + + + + + + +
ParamType
optionsobject
options.isCreateTsConfigOnlyboolean
+ ## Logger @@ -266,7 +280,7 @@ Convenience wrapper for preset console messaging and colors. ## Typescript -### Typescript~createTsConfig(dotenv, options) ⇒ undefined \| Object +### Typescript~createTsConfig(dotenv, options, settings) ⇒ undefined \| Object Create, or merge, a tsconfig file. **Kind**: inner method of [Typescript](#module_Typescript) @@ -288,11 +302,15 @@ Create, or merge, a tsconfig file. options.contextPathstring + options.isCreateTsConfigboolean + options.isMergeTsConfigboolean options.isRegenTsConfigboolean - options.languagestring + settingsobject + + settings.configFilenamestring @@ -411,10 +429,35 @@ Start webpack development or production. ## webpackConfigs * [webpackConfigs](#module_webpackConfigs) + * [~preprocessLoader(dotenv, options)](#module_webpackConfigs..preprocessLoader) ⇒ Object * [~common(dotenv, options)](#module_webpackConfigs..common) ⇒ Object * [~development(dotenv)](#module_webpackConfigs..development) ⇒ Object * [~production(dotenv)](#module_webpackConfigs..production) ⇒ Object + + +### webpackConfigs~preprocessLoader(dotenv, options) ⇒ Object +Assumption based preprocess loader + +**Kind**: inner method of [webpackConfigs](#module_webpackConfigs) + + + + + + + + + + + + + + + + +
ParamType
dotenvobject
dotenv._BUILD_SRC_DIRstring
optionsobject
options.loaderstring
+ ### webpackConfigs~common(dotenv, options) ⇒ Object @@ -445,7 +488,7 @@ Common webpack settings between environments. optionsobject - options.languagestring + options.loaderstring diff --git a/src/__tests__/__snapshots__/wp.test.js.snap b/src/__tests__/__snapshots__/wp.test.js.snap index 3ac8b4c..38685d8 100644 --- a/src/__tests__/__snapshots__/wp.test.js.snap +++ b/src/__tests__/__snapshots__/wp.test.js.snap @@ -16,17 +16,6 @@ exports[`webpack should create a basic webpack config: basic configurations 1`] }, "module": { "rules": [ - { - "test": {}, - "include": [ - "./__fixtures__/src" - ], - "use": [ - { - "loader": "babel-loader" - } - ] - }, { "test": {}, "type": "asset/resource", @@ -200,6 +189,238 @@ exports[`webpack should create a basic webpack config: basic configurations 1`] }, "module": { "rules": [ + { + "test": {}, + "type": "asset/resource", + "generator": { + "filename": "fonts/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 + } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 + } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } + }, + { + "test": {}, + "use": [ + "./node_modules/mini-css-extract-plugin/dist/loader.js", + "css-loader" + ] + } + ] + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "userOptions": {}, + "version": 5, + "options": { + "template": "auto", + "templateContent": false, + "filename": "index.html", + "publicPath": "auto", + "hash": false, + "inject": "head", + "scriptLoading": "defer", + "compile": true, + "favicon": false, + "minify": "auto", + "cache": true, + "showErrors": true, + "chunks": "all", + "excludeChunks": [], + "chunksSortMode": "auto", + "meta": {}, + "base": false, + "title": "Webpack App", + "xhtml": false + } + }, + { + "config": { + "path": "./__fixtures__/.env.development.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.development", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "_sortedModulesCache": {}, + "options": { + "filename": "[name].[contenthash:8].css", + "ignoreOrder": false, + "runtime": true, + "chunkFilename": "[name].[contenthash:8].chunk.css" + }, + "runtimeOptions": { + "linkType": "text/css" + } + } + ], + "resolve": { + "symlinks": false, + "cacheWithContext": false + }, + "mode": "development", + "optimization": { + "minimize": true, + "minimizer": [ + { + "options": { + "test": {}, + "extractComments": true, + "parallel": true, + "minimizer": { + "options": {} + } + } + }, + { + "options": { + "test": {}, + "parallel": true, + "minimizer": { + "options": { + "preset": [ + "default", + { + "mergeLonghand": false + } + ] + } + } + } + } + ], + "runtimeChunk": "single", + "splitChunks": { + "chunks": "all", + "cacheGroups": { + "vendor": { + "chunks": "all", + "name": "vendor", + "test": {} + } + } + } + } +}", +} +`; + +exports[`webpack should create a webpack config with language: language configurations 1`] = ` +{ + "dev": "{ + "context": "./__fixtures__", + "entry": { + "app": [ + "./__fixtures__/src/index.js" + ] + }, + "output": { + "filename": "[name].bundle.js", + "path": "./__fixtures__/dist", + "clean": true + }, + "module": { + "rules": [ + { + "test": {}, + "type": "asset/resource", + "generator": { + "filename": "fonts/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 + } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 + } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } + }, + { + "test": {}, + "use": [ + "./node_modules/mini-css-extract-plugin/dist/loader.js", + "css-loader" + ] + }, { "test": {}, "include": [ @@ -210,7 +431,142 @@ exports[`webpack should create a basic webpack config: basic configurations 1`] "loader": "babel-loader" } ] + } + ] + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "userOptions": {}, + "version": 5, + "options": { + "template": "auto", + "templateContent": false, + "filename": "index.html", + "publicPath": "auto", + "hash": false, + "inject": "head", + "scriptLoading": "defer", + "compile": true, + "favicon": false, + "minify": "auto", + "cache": true, + "showErrors": true, + "chunks": "all", + "excludeChunks": [], + "chunksSortMode": "auto", + "meta": {}, + "base": false, + "title": "Webpack App", + "xhtml": false + } + }, + { + "config": { + "path": "./__fixtures__/.env.development.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.development", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "_sortedModulesCache": {}, + "options": { + "filename": "[name].bundle.css", + "ignoreOrder": false, + "runtime": true, + "chunkFilename": "[name].bundle.css" }, + "runtimeOptions": { + "linkType": "text/css" + } + } + ], + "resolve": { + "symlinks": false, + "cacheWithContext": false + }, + "mode": "development", + "devtool": "eval-source-map", + "devServer": { + "host": "localhost", + "port": 3000, + "compress": true, + "historyApiFallback": true, + "hot": true, + "devMiddleware": { + "stats": "errors-warnings", + "writeToDisk": false + }, + "client": { + "overlay": false, + "progress": true + }, + "static": { + "directory": "./__fixtures__/dist" + }, + "watchFiles": { + "paths": [ + "src/**/*", + "public/**/*" + ] + } + } +}", + "prod": "{ + "context": "./__fixtures__", + "entry": { + "app": [ + "./__fixtures__/src/index.js" + ] + }, + "output": { + "filename": "[name].[contenthash:8].js", + "path": "./__fixtures__/dist", + "clean": true, + "chunkFilename": "[name].[contenthash:8].chunk.js" + }, + "module": { + "rules": [ { "test": {}, "type": "asset/resource", @@ -248,6 +604,17 @@ exports[`webpack should create a basic webpack config: basic configurations 1`] "./node_modules/mini-css-extract-plugin/dist/loader.js", "css-loader" ] + }, + { + "test": {}, + "include": [ + "./__fixtures__/src" + ], + "use": [ + { + "loader": "babel-loader" + } + ] } ] }, @@ -405,17 +772,6 @@ exports[`webpack should extend a basic webpack config using commonJS resources: }, "module": { "rules": [ - { - "test": {}, - "include": [ - "./__fixtures__/src" - ], - "use": [ - { - "loader": "babel-loader" - } - ] - }, { "test": {}, "type": "asset/resource", @@ -608,7 +964,6 @@ exports[`webpack should return specific properties: specific properties 1`] = ` { "cleanDist": [Function], "createWpConfig": [Function], - "merge": [Function], "startWp": [Function], "startWpErrorStatsHandler": [Function], } diff --git a/src/__tests__/__snapshots__/wpConfigs.test.js.snap b/src/__tests__/__snapshots__/wpConfigs.test.js.snap index 17fb65e..f5b0e95 100644 --- a/src/__tests__/__snapshots__/wpConfigs.test.js.snap +++ b/src/__tests__/__snapshots__/wpConfigs.test.js.snap @@ -1,6 +1,29 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`webpackConfigs should return a common configuration object: common dev 1`] = ` +exports[`webpackConfigs should return a common configuration object: common dev, prod hashes 1`] = ` +[ + { + "devHash": "09dbe6c79e6e659a16607250a6517521", + "isEqual": true, + "loader": "js", + "prodHash": "09dbe6c79e6e659a16607250a6517521", + }, + { + "devHash": "09dbe6c79e6e659a16607250a6517521", + "isEqual": true, + "loader": "ts", + "prodHash": "09dbe6c79e6e659a16607250a6517521", + }, + { + "devHash": "09dbe6c79e6e659a16607250a6517521", + "isEqual": true, + "loader": "none", + "prodHash": "09dbe6c79e6e659a16607250a6517521", + }, +] +`; + +exports[`webpackConfigs should return a common configuration object: common dev: js 1`] = ` "{ "context": "./__fixtures__", "entry": { @@ -17,15 +40,214 @@ exports[`webpackConfigs should return a common configuration object: common dev "rules": [ { "test": {}, - "include": [ - "./__fixtures__/src" - ], - "use": [ - { - "loader": "babel-loader" + "type": "asset/resource", + "generator": { + "filename": "fonts/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 + } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } + }, + { + "test": {}, + "use": [ + "./node_modules/mini-css-extract-plugin/dist/loader.js", + "css-loader" ] + } + ] + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "userOptions": {}, + "version": 5, + "options": { + "template": "auto", + "templateContent": false, + "filename": "index.html", + "publicPath": "auto", + "hash": false, + "inject": "head", + "scriptLoading": "defer", + "compile": true, + "favicon": false, + "minify": "auto", + "cache": true, + "showErrors": true, + "chunks": "all", + "excludeChunks": [], + "chunksSortMode": "auto", + "meta": {}, + "base": false, + "title": "Webpack App", + "xhtml": false + } + } + ], + "resolve": { + "symlinks": false, + "cacheWithContext": false + } +}" +`; + +exports[`webpackConfigs should return a common configuration object: common dev: none 1`] = ` +"{ + "context": "./__fixtures__", + "entry": { + "app": [ + "./__fixtures__/src/index.js" + ] + }, + "output": { + "filename": "[name].bundle.js", + "path": "./__fixtures__/dist", + "clean": true + }, + "module": { + "rules": [ + { + "test": {}, + "type": "asset/resource", + "generator": { + "filename": "fonts/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 + } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } + }, + { + "test": {}, + "type": "asset", + "parser": { + "dataUrlCondition": { + "maxSize": 5000 + } + }, + "generator": { + "filename": "images/[hash][ext][query]" + } }, + { + "test": {}, + "use": [ + "./node_modules/mini-css-extract-plugin/dist/loader.js", + "css-loader" + ] + } + ] + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "userOptions": {}, + "version": 5, + "options": { + "template": "auto", + "templateContent": false, + "filename": "index.html", + "publicPath": "auto", + "hash": false, + "inject": "head", + "scriptLoading": "defer", + "compile": true, + "favicon": false, + "minify": "auto", + "cache": true, + "showErrors": true, + "chunks": "all", + "excludeChunks": [], + "chunksSortMode": "auto", + "meta": {}, + "base": false, + "title": "Webpack App", + "xhtml": false + } + } + ], + "resolve": { + "symlinks": false, + "cacheWithContext": false + } +}" +`; + +exports[`webpackConfigs should return a common configuration object: common dev: ts 1`] = ` +"{ + "context": "./__fixtures__", + "entry": { + "app": [ + "./__fixtures__/src/index.js" + ] + }, + "output": { + "filename": "[name].bundle.js", + "path": "./__fixtures__/dist", + "clean": true + }, + "module": { + "rules": [ { "test": {}, "type": "asset/resource", @@ -116,15 +338,30 @@ exports[`webpackConfigs should return a common configuration object: common dev }" `; -exports[`webpackConfigs should return a common configuration object: common dev, prod hashes 1`] = ` -{ - "devHash": "1b527ed1b6f2935342c19ba86e27c4e2", - "isEqual": true, - "prodHash": "1b527ed1b6f2935342c19ba86e27c4e2", -} +exports[`webpackConfigs should return a development configuration object: development dev, prod hashes 1`] = ` +[ + { + "devHash": "f055fd71c64003ac9128c4107231e879", + "isEqual": false, + "loader": "js", + "prodHash": "6f31daec8d4bfba244448cfbc2f4edcf", + }, + { + "devHash": "f055fd71c64003ac9128c4107231e879", + "isEqual": false, + "loader": "ts", + "prodHash": "6f31daec8d4bfba244448cfbc2f4edcf", + }, + { + "devHash": "f055fd71c64003ac9128c4107231e879", + "isEqual": false, + "loader": "none", + "prodHash": "6f31daec8d4bfba244448cfbc2f4edcf", + }, +] `; -exports[`webpackConfigs should return a development configuration object: development dev 1`] = ` +exports[`webpackConfigs should return a development configuration object: development dev: js 1`] = ` "{ "mode": "development", "devtool": "eval-source-map", @@ -201,49 +438,281 @@ exports[`webpackConfigs should return a development configuration object: develo }" `; -exports[`webpackConfigs should return a development configuration object: development dev, prod hashes 1`] = ` -{ - "devHash": "f055fd71c64003ac9128c4107231e879", - "isEqual": false, - "prodHash": "6f31daec8d4bfba244448cfbc2f4edcf", -} -`; - -exports[`webpackConfigs should return a production configuration object: production dev, prod hashes 1`] = ` -{ - "devHash": "9538aadb737ec81df9a67275a1d4e93f", - "isEqual": false, - "prodHash": "4635888960b8aaecc46599deb39c005e", -} -`; - -exports[`webpackConfigs should return a production configuration object: production prod 1`] = ` +exports[`webpackConfigs should return a development configuration object: development dev: none 1`] = ` "{ - "mode": "production", - "output": { - "chunkFilename": "[name].[contenthash:8].chunk.js", - "filename": "[name].[contenthash:8].js" - }, - "optimization": { - "minimize": true, - "minimizer": [ - { - "options": { - "test": {}, - "extractComments": true, - "parallel": true, - "minimizer": { - "options": {} - } - } - }, - { - "options": { - "test": {}, - "parallel": true, - "minimizer": { - "options": { - "preset": [ + "mode": "development", + "devtool": "eval-source-map", + "devServer": { + "host": "localhost", + "port": 3000, + "compress": true, + "historyApiFallback": true, + "hot": true, + "devMiddleware": { + "stats": "errors-warnings", + "writeToDisk": false + }, + "client": { + "overlay": false, + "progress": true + }, + "static": { + "directory": "./__fixtures__/dist" + }, + "watchFiles": { + "paths": [ + "src/**/*", + "public/**/*" + ] + } + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.development.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.development", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "_sortedModulesCache": {}, + "options": { + "filename": "[name].bundle.css", + "ignoreOrder": false, + "runtime": true, + "chunkFilename": "[name].bundle.css" + }, + "runtimeOptions": { + "linkType": "text/css" + } + } + ] +}" +`; + +exports[`webpackConfigs should return a development configuration object: development dev: ts 1`] = ` +"{ + "mode": "development", + "devtool": "eval-source-map", + "devServer": { + "host": "localhost", + "port": 3000, + "compress": true, + "historyApiFallback": true, + "hot": true, + "devMiddleware": { + "stats": "errors-warnings", + "writeToDisk": false + }, + "client": { + "overlay": false, + "progress": true + }, + "static": { + "directory": "./__fixtures__/dist" + }, + "watchFiles": { + "paths": [ + "src/**/*", + "public/**/*" + ] + } + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.development.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.development", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "_sortedModulesCache": {}, + "options": { + "filename": "[name].bundle.css", + "ignoreOrder": false, + "runtime": true, + "chunkFilename": "[name].bundle.css" + }, + "runtimeOptions": { + "linkType": "text/css" + } + } + ] +}" +`; + +exports[`webpackConfigs should return a preprocessLoader configuration object: language dev, prod hashes 1`] = ` +[ + { + "devHash": "622840d4852c749c1df5e7325bca73a1", + "isEqual": true, + "loader": "js", + "prodHash": "622840d4852c749c1df5e7325bca73a1", + }, + { + "devHash": "7149a7a85fe5bc99f81782452e2c0ced", + "isEqual": true, + "loader": "ts", + "prodHash": "7149a7a85fe5bc99f81782452e2c0ced", + }, + { + "devHash": "49e595be76828acf4f2a3617fea9a378", + "isEqual": true, + "loader": "none", + "prodHash": "49e595be76828acf4f2a3617fea9a378", + }, +] +`; + +exports[`webpackConfigs should return a preprocessLoader configuration object: preprocessLoader dev: js 1`] = ` +"{ + "module": { + "rules": [ + { + "test": {}, + "include": [ + "./__fixtures__/src" + ], + "use": [ + { + "loader": "babel-loader" + } + ] + } + ] + } +}" +`; + +exports[`webpackConfigs should return a preprocessLoader configuration object: preprocessLoader dev: none 1`] = ` +"{ + "module": { + "rules": [] + } +}" +`; + +exports[`webpackConfigs should return a preprocessLoader configuration object: preprocessLoader dev: ts 1`] = ` +"{ + "module": { + "rules": [ + { + "test": {}, + "include": [ + "./__fixtures__/src" + ], + "use": [ + { + "loader": "ts-loader" + } + ] + } + ] + } +}" +`; + +exports[`webpackConfigs should return a production configuration object: production dev, prod hashes 1`] = ` +[ + { + "devHash": "9538aadb737ec81df9a67275a1d4e93f", + "isEqual": false, + "loader": "js", + "prodHash": "4635888960b8aaecc46599deb39c005e", + }, + { + "devHash": "9538aadb737ec81df9a67275a1d4e93f", + "isEqual": false, + "loader": "ts", + "prodHash": "4635888960b8aaecc46599deb39c005e", + }, + { + "devHash": "9538aadb737ec81df9a67275a1d4e93f", + "isEqual": false, + "loader": "none", + "prodHash": "4635888960b8aaecc46599deb39c005e", + }, +] +`; + +exports[`webpackConfigs should return a production configuration object: production dev: js 1`] = ` +"{ + "mode": "development", + "output": { + "chunkFilename": "[name].[contenthash:8].chunk.js", + "filename": "[name].[contenthash:8].js" + }, + "optimization": { + "minimize": true, + "minimizer": [ + { + "options": { + "test": {}, + "extractComments": true, + "parallel": true, + "minimizer": { + "options": {} + } + } + }, + { + "options": { + "test": {}, + "parallel": true, + "minimizer": { + "options": { + "preset": [ "default", { "mergeLonghand": false @@ -269,7 +738,23 @@ exports[`webpackConfigs should return a production configuration object: product "plugins": [ { "config": { - "path": "./__fixtures__/.env.production.local", + "path": "./__fixtures__/.env.development.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.development", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.local", "prefix": "process.env.", "systemvars": true, "silent": true @@ -277,7 +762,187 @@ exports[`webpackConfigs should return a production configuration object: product }, { "config": { - "path": "./__fixtures__/.env.production", + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "_sortedModulesCache": {}, + "options": { + "filename": "[name].[contenthash:8].css", + "ignoreOrder": false, + "runtime": true, + "chunkFilename": "[name].[contenthash:8].chunk.css" + }, + "runtimeOptions": { + "linkType": "text/css" + } + } + ] +}" +`; + +exports[`webpackConfigs should return a production configuration object: production dev: none 1`] = ` +"{ + "mode": "development", + "output": { + "chunkFilename": "[name].[contenthash:8].chunk.js", + "filename": "[name].[contenthash:8].js" + }, + "optimization": { + "minimize": true, + "minimizer": [ + { + "options": { + "test": {}, + "extractComments": true, + "parallel": true, + "minimizer": { + "options": {} + } + } + }, + { + "options": { + "test": {}, + "parallel": true, + "minimizer": { + "options": { + "preset": [ + "default", + { + "mergeLonghand": false + } + ] + } + } + } + } + ], + "runtimeChunk": "single", + "splitChunks": { + "chunks": "all", + "cacheGroups": { + "vendor": { + "chunks": "all", + "name": "vendor", + "test": {} + } + } + } + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.development.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.development", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "_sortedModulesCache": {}, + "options": { + "filename": "[name].[contenthash:8].css", + "ignoreOrder": false, + "runtime": true, + "chunkFilename": "[name].[contenthash:8].chunk.css" + }, + "runtimeOptions": { + "linkType": "text/css" + } + } + ] +}" +`; + +exports[`webpackConfigs should return a production configuration object: production dev: ts 1`] = ` +"{ + "mode": "development", + "output": { + "chunkFilename": "[name].[contenthash:8].chunk.js", + "filename": "[name].[contenthash:8].js" + }, + "optimization": { + "minimize": true, + "minimizer": [ + { + "options": { + "test": {}, + "extractComments": true, + "parallel": true, + "minimizer": { + "options": {} + } + } + }, + { + "options": { + "test": {}, + "parallel": true, + "minimizer": { + "options": { + "preset": [ + "default", + { + "mergeLonghand": false + } + ] + } + } + } + } + ], + "runtimeChunk": "single", + "splitChunks": { + "chunks": "all", + "cacheGroups": { + "vendor": { + "chunks": "all", + "name": "vendor", + "test": {} + } + } + } + }, + "plugins": [ + { + "config": { + "path": "./__fixtures__/.env.development.local", + "prefix": "process.env.", + "systemvars": true, + "silent": true + } + }, + { + "config": { + "path": "./__fixtures__/.env.development", "prefix": "process.env.", "systemvars": true, "silent": true @@ -319,6 +984,7 @@ exports[`webpackConfigs should return specific properties: specific properties 1 { "common": [Function], "development": [Function], + "preprocessLoader": [Function], "production": [Function], } `; diff --git a/src/__tests__/ts.test.js b/src/__tests__/ts.test.js index 9f3878b..b157c1c 100644 --- a/src/__tests__/ts.test.js +++ b/src/__tests__/ts.test.js @@ -10,7 +10,7 @@ describe('Typescript', () => { it('should create a basic tsconfig', () => { const results = ts.createTsConfig( { _BUILD_DIST_DIR: path.join(contextPath, 'dist') }, - { language: 'ts', contextPath: tempFixturePath, isRegenTsConfig: true } + { loader: 'ts', contextPath: tempFixturePath, isCreateTsConfig: true, isRegenTsConfig: true } ); expect(results).toMatchSnapshot('basic'); @@ -19,7 +19,13 @@ describe('Typescript', () => { it('should create a tsconfig with a base template', () => { const results = ts.createTsConfig( { _BUILD_DIST_DIR: path.join(contextPath, 'dist') }, - { baseTsConfig: 'create-react-app', language: 'ts', contextPath: tempFixturePath, isRegenTsConfig: true } + { + baseTsConfig: 'create-react-app', + loader: 'ts', + contextPath: tempFixturePath, + isCreateTsConfig: true, + isRegenTsConfig: true + } ); expect(results).toMatchSnapshot('base template'); @@ -31,8 +37,9 @@ describe('Typescript', () => { { _BUILD_DIST_DIR }, { baseTsConfig: 'create-react-app', - language: 'ts', + loader: 'ts', contextPath: tempFixturePath, + isCreateTsConfig: true, isRegenTsConfig: true } ); @@ -41,8 +48,9 @@ describe('Typescript', () => { { _BUILD_DIST_DIR }, { baseTsConfig: 'strictest', - language: 'ts', + loader: 'ts', contextPath: tempFixturePath, + isCreateTsConfig: true, isMergeTsConfig: true } ); diff --git a/src/__tests__/wp.test.js b/src/__tests__/wp.test.js index 5e05a44..5be8979 100644 --- a/src/__tests__/wp.test.js +++ b/src/__tests__/wp.test.js @@ -15,6 +15,13 @@ describe('webpack', () => { } }; + /** + * Provide a consistent way of processing configs. + * + * @param {object} obj + * @param {boolean} isHash + * @returns {string} + */ const cleanConfig = (obj, isHash) => { const contents = JSON.stringify(obj, null, 2).replace(/"[a-z0-9/-_.,*()\s]*\/weldable\//gi, '"./'); if (isHash) { @@ -48,6 +55,27 @@ describe('webpack', () => { mockClear(); }); + it('should create a webpack config with language', async () => { + const { mockClear } = mockObjectProperty(OPTIONS, { + dotenv: { + ...baseOptions.dotenv + }, + loader: 'js' + }); + + const dev = await wp.createWpConfig({ + nodeEnv: 'development' + }); + + const prod = await wp.createWpConfig(); + + expect({ + dev: cleanConfig(dev), + prod: cleanConfig(prod) + }).toMatchSnapshot('language configurations'); + mockClear(); + }); + it('should extend a basic webpack config using commonJS resources', async () => { const { mockClear } = mockObjectProperty(OPTIONS, { dotenv: { diff --git a/src/__tests__/wpConfigs.test.js b/src/__tests__/wpConfigs.test.js index 053fa8b..3bf6e81 100644 --- a/src/__tests__/wpConfigs.test.js +++ b/src/__tests__/wpConfigs.test.js @@ -15,6 +15,13 @@ describe('webpackConfigs', () => { } }; + /** + * Provide a consistent way of processing configs. + * + * @param {object} obj + * @param {boolean} isHash + * @returns {string} + */ const cleanConfig = (obj, isHash) => { const contents = JSON.stringify(obj, null, 2).replace(/"[a-z0-9/-_.,*()\s]*\/weldable\//gi, '"./'); if (isHash) { @@ -24,91 +31,78 @@ describe('webpackConfigs', () => { return contents; }; - it('should return specific properties', () => { - expect(wpConfigs).toMatchSnapshot('specific properties'); - }); - - it('should return a common configuration object', () => { + /** + * Test multiple configurations consistently + * + * @param {Function} method + * @param {string} loader + * @returns {{prodHash: string, isEqual: boolean, loader, devHash: string}} + */ + const processConfigIntoHashes = (method, loader = 'none') => { const { mockClear: mockDevClear } = mockObjectProperty(OPTIONS, { dotenv: { ...baseOptions.dotenv - } + }, + loader }); - expect(cleanConfig(wpConfigs.common())).toMatchSnapshot('common dev'); - const devHash = cleanConfig(wpConfigs.common(), true); + expect(cleanConfig(method())).toMatchSnapshot(`${method.name} dev: ${loader}`); + const devHash = cleanConfig(method(), true); mockDevClear(); const { mockClear: mockProdClear } = mockObjectProperty(OPTIONS, { dotenv: { ...baseOptions.dotenv, NODE_ENV: 'production' - } + }, + loader }); - const prodHash = cleanConfig(wpConfigs.common(), true); + const prodHash = cleanConfig(method(), true); + mockProdClear(); - expect({ + return { + loader, isEqual: devHash === prodHash, devHash, prodHash - }).toMatchSnapshot('common dev, prod hashes'); - mockProdClear(); - }); - - it('should return a development configuration object', () => { - const { mockClear: mockDevClear } = mockObjectProperty(OPTIONS, { - dotenv: { - ...baseOptions.dotenv - } - }); + }; + }; - expect(cleanConfig(wpConfigs.development())).toMatchSnapshot('development dev'); - const devHash = cleanConfig(wpConfigs.development(), true); - mockDevClear(); + it('should return specific properties', () => { + expect(wpConfigs).toMatchSnapshot('specific properties'); + }); - const { mockClear: mockProdClear } = mockObjectProperty(OPTIONS, { - dotenv: { - ...baseOptions.dotenv, - NODE_ENV: 'production' - } - }); + it('should return a preprocessLoader configuration object', () => { + expect([ + processConfigIntoHashes(wpConfigs.preprocessLoader, 'js'), + processConfigIntoHashes(wpConfigs.preprocessLoader, 'ts'), + processConfigIntoHashes(wpConfigs.preprocessLoader) + ]).toMatchSnapshot('language dev, prod hashes'); + }); - const prodHash = cleanConfig(wpConfigs.development(), true); + it('should return a common configuration object', () => { + expect([ + processConfigIntoHashes(wpConfigs.common, 'js'), + processConfigIntoHashes(wpConfigs.common, 'ts'), + processConfigIntoHashes(wpConfigs.common) + ]).toMatchSnapshot('common dev, prod hashes'); + }); - expect({ - isEqual: devHash === prodHash, - devHash, - prodHash - }).toMatchSnapshot('development dev, prod hashes'); - mockProdClear(); + it('should return a development configuration object', () => { + expect([ + processConfigIntoHashes(wpConfigs.development, 'js'), + processConfigIntoHashes(wpConfigs.development, 'ts'), + processConfigIntoHashes(wpConfigs.development) + ]).toMatchSnapshot('development dev, prod hashes'); }); it('should return a production configuration object', () => { - const { mockClear: mockProdClear } = mockObjectProperty(OPTIONS, { - dotenv: { - ...baseOptions.dotenv, - NODE_ENV: 'production' - } - }); - - expect(cleanConfig(wpConfigs.production())).toMatchSnapshot('production prod'); - const prodHash = cleanConfig(wpConfigs.production(), true); - mockProdClear(); - - const { mockClear: mockDevClear } = mockObjectProperty(OPTIONS, { - dotenv: { - ...baseOptions.dotenv - } - }); - - const devHash = cleanConfig(wpConfigs.production(), true); - - expect({ - isEqual: devHash === prodHash, - devHash, - prodHash - }).toMatchSnapshot('production dev, prod hashes'); - mockDevClear(); + // This is expected to be false for result hashes, NODE_ENV is displayed in the obj + expect([ + processConfigIntoHashes(wpConfigs.production, 'js'), + processConfigIntoHashes(wpConfigs.production, 'ts'), + processConfigIntoHashes(wpConfigs.production) + ]).toMatchSnapshot('production dev, prod hashes'); }); }); diff --git a/src/index.js b/src/index.js index bdcee66..48cfe42 100644 --- a/src/index.js +++ b/src/index.js @@ -11,10 +11,17 @@ const { createTsConfig } = require('./ts'); /** * Organize package functionality. * + * @param {object} options + * @param {boolean} options.isCreateTsConfigOnly * @returns {Promise} */ -const weldable = async () => { +const weldable = async ({ isCreateTsConfigOnly } = OPTIONS) => { createTsConfig(); + + if (isCreateTsConfigOnly) { + return; + } + const webpackConfig = await createWpConfig(); cleanDist(); await startWp(webpackConfig); diff --git a/src/ts.js b/src/ts.js index 68902c5..a83fb2f 100644 --- a/src/ts.js +++ b/src/ts.js @@ -15,19 +15,27 @@ const { consoleMessage } = require('./logger'); * @param {object} options * @param {string} options.baseTsConfig * @param {string} options.contextPath + * @param {boolean} options.isCreateTsConfig * @param {boolean} options.isMergeTsConfig * @param {boolean} options.isRegenTsConfig - * @param {string} options.language + * @param {object} settings + * @param {string} settings.configFilename * @returns {undefined|{compilerOptions: {noEmit: boolean, allowJs: boolean, outDir: string}}} */ const createTsConfig = ( { _BUILD_DIST_DIR: DIST_DIR } = OPTIONS.dotenv || {}, - { baseTsConfig, contextPath, isMergeTsConfig, isRegenTsConfig, language } = OPTIONS + { baseTsConfig, contextPath, isCreateTsConfig, isMergeTsConfig, isRegenTsConfig } = OPTIONS, + { configFilename = 'tsconfig.json' } = {} ) => { - const currentConfigPath = path.join(contextPath, 'tsconfig.json'); + const currentConfigPath = path.join(contextPath, configFilename); const isCurrentConfig = fs.existsSync(currentConfigPath); - if (language !== 'ts' || (isCurrentConfig && !isRegenTsConfig && !isMergeTsConfig)) { + if (isCurrentConfig) { + consoleMessage.warn(`Current ${configFilename} found: ${currentConfigPath}`); + } + + if (!isCreateTsConfig) { + consoleMessage.warn(`Ignoring ${configFilename}`); return undefined; } @@ -39,16 +47,16 @@ const createTsConfig = ( // eslint-disable-next-line global-require currentConfig = require(currentConfigPath); } catch (e) { - consoleMessage.warn(`No current tsconfig.`); + consoleMessage.warn(`No ${configFilename} found.`); } } if (baseTsConfig) { try { // eslint-disable-next-line global-require - presetConfig = require(`@tsconfig/${baseTsConfig}/tsconfig.json`); + presetConfig = require(`@tsconfig/${baseTsConfig}/${configFilename}`); } catch (e) { - consoleMessage.warn(`No base tsconfig specified, using basic properties only.`); + consoleMessage.warn(`No preset ${configFilename} specified, using basic properties only.`); } } @@ -66,9 +74,18 @@ const createTsConfig = ( createFile(`${JSON.stringify(customTsConfig, null, 2)}\n`, { dir: contextPath, - filename: 'tsconfig.json' + filename: configFilename }); + if (isCreateTsConfig) { + consoleMessage.success( + `${(isMergeTsConfig && 'Merged') || (isRegenTsConfig && 'Regenerated') || 'Created'} config: ${path.join( + contextPath, + configFilename + )}` + ); + } + return customTsConfig; }; diff --git a/src/wp.js b/src/wp.js index 0ddd85f..80b6113 100644 --- a/src/wp.js +++ b/src/wp.js @@ -5,7 +5,7 @@ const { rimrafSync } = require('rimraf'); const { merge } = require('webpack-merge'); const { createFile, dynamicImport, errorMessageHandler, isPromise, OPTIONS } = require('./global'); const { consoleMessage } = require('./logger'); -const { common, development, production } = require('./wpConfigs'); +const { common, development, preprocessLoader, production } = require('./wpConfigs'); /** * @module webpack @@ -21,6 +21,7 @@ const cleanDist = ({ _BUILD_DIST_DIR: DIST_DIR } = OPTIONS.dotenv || {}) => { rimrafSync(path.join(DIST_DIR, '*'), { glob: true }); }; +// ToDo: review allowing mergeWithCustom /** * Webpack merge base configuration files. If available merge extended configuration files. * @@ -31,7 +32,7 @@ const cleanDist = ({ _BUILD_DIST_DIR: DIST_DIR } = OPTIONS.dotenv || {}) => { * @returns {Promise} */ const createWpConfig = async ({ nodeEnv, dotenv = {}, extendedConfigs } = OPTIONS) => { - const baseConfigs = [common(), (nodeEnv === 'development' && development()) || production()]; + const baseConfigs = [common(), preprocessLoader(), (nodeEnv === 'development' && development()) || production()]; const extended = []; if (Array.isArray(extendedConfigs) && extendedConfigs?.length) { @@ -164,7 +165,6 @@ const startWp = async ( module.exports = { cleanDist, createWpConfig, - merge, startWp, startWpErrorStatsHandler }; diff --git a/src/wpConfigs.js b/src/wpConfigs.js index cc08643..5966dc4 100644 --- a/src/wpConfigs.js +++ b/src/wpConfigs.js @@ -15,6 +15,50 @@ const { setupWebpackDotenvFilesForEnv } = require('./dotenv'); * @module webpackConfigs */ +/** + * Assumption based preprocess loader + * + * @param {object} dotenv + * @param {string} dotenv._BUILD_SRC_DIR + * @param {object} options + * @param {string} options.loader + * @returns {{module: {rules: Array}}} + */ +const preprocessLoader = ({ _BUILD_SRC_DIR: SRC_DIR = '' } = OPTIONS.dotenv || {}, { loader } = OPTIONS) => ({ + module: { + rules: (() => { + switch (loader) { + case 'js': + return [ + { + test: /\.(jsx|js)?$/, + include: [SRC_DIR], + use: [ + { + loader: 'babel-loader' + } + ] + } + ]; + case 'ts': + return [ + { + test: /\.(tsx|ts|js)?$/, + include: [SRC_DIR], + use: [ + { + loader: 'ts-loader' + } + ] + } + ]; + default: + return []; + } + })() + } +}); + /** * Common webpack settings between environments. * @@ -26,7 +70,7 @@ const { setupWebpackDotenvFilesForEnv } = require('./dotenv'); * @param {string} dotenv._BUILD_STATIC_DIR * @param {string} dotenv._BUILD_UI_NAME * @param {object} options - * @param {string} options.language + * @param {string} options.loader * @returns {{output: {path: string, filename: string, publicPath: string, clean: boolean}, entry: {app: string}, * resolve: {cacheWithContext: boolean, symlinks: boolean}, plugins: any[], module: {rules: Array}}} */ @@ -39,7 +83,7 @@ const common = ( _BUILD_STATIC_DIR: STATIC_DIR = '', _BUILD_UI_NAME: UI_NAME } = OPTIONS.dotenv || {}, - { language } = OPTIONS + { loader } = OPTIONS ) => ({ context: RELATIVE_DIRNAME, entry: { @@ -49,13 +93,13 @@ const common = ( const entryFilesSet = new Set([ path.join(SRC_DIR, `index.js`), path.join(SRC_DIR, `index.jsx`), - path.join(SRC_DIR, `index.${language}`), - path.join(SRC_DIR, `index.${language}x`) + path.join(SRC_DIR, `index.${loader}`), + path.join(SRC_DIR, `index.${loader}x`) ]); entryFiles = Array.from(entryFilesSet).filter(file => fs.existsSync(file)); if (!entryFiles.length) { - consoleMessage.warn(`webpack app entry file error: Missing entry/app file. Expected index.(js|ts|x)`); + consoleMessage.warn(`webpack app entry file error: Missing entry/app file. Expected index.(${loader}|x)`); } } catch (e) { consoleMessage.error(`webpack app entry file error: ${e.message}`); @@ -72,15 +116,6 @@ const common = ( }, module: { rules: [ - { - test: (language === 'ts' && /\.(tsx|ts|jsx|js)?$/) || /\.(jsx|js)?$/, - include: [SRC_DIR], - use: [ - { - loader: (language === 'ts' && 'ts-loader') || 'babel-loader' - } - ] - }, { test: /\.(svg|ttf|eot|woff|woff2)$/, include: input => input.indexOf('fonts') > -1 || input.indexOf('icon') > -1, @@ -293,5 +328,6 @@ const production = ({ NODE_ENV: MODE, _BUILD_RELATIVE_DIRNAME: RELATIVE_DIRNAME module.exports = { common, development, + preprocessLoader, production };