diff --git a/examples/plugin/src/app/index.css b/examples/plugin/src/app/index.css index 83d30f767..98ca2057d 100644 --- a/examples/plugin/src/app/index.css +++ b/examples/plugin/src/app/index.css @@ -4,5 +4,5 @@ body { .site-title a { color: slategray !important; - background-color: cornsilk !important; + background-color: aqua !important; } diff --git a/examples/plugin/src/app/index.js b/examples/plugin/src/app/index.js index 205723c6c..9ffc58335 100644 --- a/examples/plugin/src/app/index.js +++ b/examples/plugin/src/app/index.js @@ -13,7 +13,7 @@ logger(); // Dynamic import import('./modules/dynamic.js').then(({ default: _ }) => { - console.log('I am dynamically imported'); + console.log('I am dynamically imported!'); _(); }); diff --git a/examples/plugin/src/app/modules/dynamic.js b/examples/plugin/src/app/modules/dynamic.js index 666e721e6..3b2c79085 100644 --- a/examples/plugin/src/app/modules/dynamic.js +++ b/examples/plugin/src/app/modules/dynamic.js @@ -1,3 +1,3 @@ export default function iAmGroot() { - console.log('I am dynamic groot! With Hot reloading!😱'); + console.log('I am dynamic groot! With Hot reloading!😱💩'); } diff --git a/examples/plugin/src/app/modules/logger.js b/examples/plugin/src/app/modules/logger.js index d0fa39b50..b3d462cfb 100644 --- a/examples/plugin/src/app/modules/logger.js +++ b/examples/plugin/src/app/modules/logger.js @@ -1,3 +1,3 @@ export default function logger() { - console.log('Load me 🤟🎉💥'); + console.log('Load me 🤟🎉💥😜'); } diff --git a/packages/scripts/__tests__/config/WebpackConfigHelper.spec.ts b/packages/scripts/__tests__/config/WebpackConfigHelper.spec.ts index c8cf16483..aefeeef27 100644 --- a/packages/scripts/__tests__/config/WebpackConfigHelper.spec.ts +++ b/packages/scripts/__tests__/config/WebpackConfigHelper.spec.ts @@ -25,6 +25,7 @@ function getConfigFromProjectAndServer( outputPath: pCfg.outputPath, hasReact: pCfg.hasReact, hasSass: pCfg.hasSass, + hasFlow: pCfg.hasFlow, bannerConfig: pCfg.bannerConfig, alias: pCfg.alias, optimizeSplitChunks: pCfg.optimizeSplitChunks, diff --git a/packages/scripts/__tests__/config/__snapshots__/WebpackConfigHelper.spec.ts.snap b/packages/scripts/__tests__/config/__snapshots__/WebpackConfigHelper.spec.ts.snap index 5e7bfd7e1..2ca304212 100644 --- a/packages/scripts/__tests__/config/__snapshots__/WebpackConfigHelper.spec.ts.snap +++ b/packages/scripts/__tests__/config/__snapshots__/WebpackConfigHelper.spec.ts.snap @@ -36,6 +36,7 @@ Object { Array [ "@wpackio/base", Object { + "hasFlow": false, "hasReact": true, }, ], diff --git a/packages/scripts/package.json b/packages/scripts/package.json index cdcd1fd9b..155e1b095 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -20,6 +20,7 @@ "private": false, "dependencies": { "@babel/core": "^7.1.0", + "@babel/preset-flow": "^7.0.0", "@babel/preset-typescript": "^7.1.0", "@types/browser-sync": "^0.0.42", "@types/figlet": "^1.2.0", diff --git a/packages/scripts/src/config/CreateWebpackConfig.ts b/packages/scripts/src/config/CreateWebpackConfig.ts index 1797bc1ee..3972d0ab5 100644 --- a/packages/scripts/src/config/CreateWebpackConfig.ts +++ b/packages/scripts/src/config/CreateWebpackConfig.ts @@ -135,6 +135,7 @@ export class CreateWebpackConfig { slug, hasReact, hasSass, + hasFlow, bannerConfig, alias, optimizeSplitChunks, @@ -152,6 +153,7 @@ export class CreateWebpackConfig { port, hasReact, hasSass, + hasFlow, bannerConfig, alias, optimizeSplitChunks, diff --git a/packages/scripts/src/config/WebpackConfigHelper.ts b/packages/scripts/src/config/WebpackConfigHelper.ts index 6ae79b172..c49c832a8 100644 --- a/packages/scripts/src/config/WebpackConfigHelper.ts +++ b/packages/scripts/src/config/WebpackConfigHelper.ts @@ -1,4 +1,7 @@ -import { babelPreset } from '@wpackio/babel-preset-base/lib/preset'; +import { + babelPreset, + PresetOptions, +} from '@wpackio/babel-preset-base/lib/preset'; import cleanWebpackPlugin from 'clean-webpack-plugin'; import miniCssExtractPlugin from 'mini-css-extract-plugin'; import path from 'path'; @@ -25,10 +28,15 @@ export interface WebpackConfigHelperConfig { outputPath: ProjectConfig['outputPath']; hasReact: ProjectConfig['hasReact']; hasSass: ProjectConfig['hasSass']; + hasFlow: ProjectConfig['hasFlow']; + jsBabelPresetOptions?: ProjectConfig['jsBabelPresetOptions']; + tsBabelPresetOptions?: ProjectConfig['tsBabelPresetOptions']; + jsBabelOverride?: ProjectConfig['jsBabelOverride']; + tsBabelOverride?: ProjectConfig['tsBabelOverride']; bannerConfig: BannerConfig; alias?: ProjectConfig['alias']; optimizeSplitChunks: ProjectConfig['optimizeSplitChunks']; - publicPath: string; + publicPath: string; // Not used right now, but maybe we will need it in future? publicPathUrl: string; } @@ -62,8 +70,6 @@ export class WebpackConfigHelper { */ private env: 'development' | 'production'; - private publicPath: string; - /** * Create an instance of GetEntryAndOutput class. */ @@ -94,7 +100,6 @@ export class WebpackConfigHelper { const { name } = this.file; this.outputInnerDir = slugify(name, { lower: true }); this.outputPath = path.join(this.cwd, outputPath); - this.publicPath = config.publicPath; } /** @@ -264,17 +269,32 @@ ${bannerConfig.copyrightText}${bannerConfig.credit ? creditNote : ''}`, * Get module object for webpack, depending on environment. */ public getModule(): webpack.Module { - const { hasReact, hasSass } = this.config; + const { hasReact, hasSass, hasFlow } = this.config; // create the babel rules for es6+ code - const jsPresets: babelPreset[] = [['@wpackio/base', { hasReact }]]; + const jsPresets: babelPreset[] = [ + [ + '@wpackio/base', + this.getBabelPresetOptions( + { hasReact, hasFlow }, + this.config.jsBabelPresetOptions + ), + ], + ]; + // Add flow if needed + if (this.config.hasFlow) { + jsPresets.push(['@babel/preset-flow']); + } const jsRules: webpack.RuleSetRule = { test: /\.m?jsx?$/, use: [ { loader: 'babel-loader', - options: { - presets: jsPresets, - }, + options: this.getOverrideWebpackRuleOptions( + { + presets: jsPresets, + }, + this.config.jsBabelOverride + ), }, ], exclude: /(node_modules|bower_components)/, @@ -282,7 +302,13 @@ ${bannerConfig.copyrightText}${bannerConfig.credit ? creditNote : ''}`, // create the babel rules for typescript code const tsPresets: babelPreset[] = [ - ['@wpackio/base', { hasReact }], + [ + '@wpackio/base', + this.getBabelPresetOptions( + { hasReact }, + this.config.tsBabelPresetOptions + ), + ], ['@babel/preset-typescript'], ]; const tsRules: webpack.RuleSetRule = { @@ -290,15 +316,18 @@ ${bannerConfig.copyrightText}${bannerConfig.credit ? creditNote : ''}`, use: [ { loader: 'babel-loader', - options: { - presets: tsPresets, - // We don't need plugin-proposal-class-properties - // because taken care of by @wpackio/base - // '@babel/proposal-class-properties', - // We don't need object-rest-spread because it is - // already in stage-4 and taken care of by preset-env - // '@babel/proposal-object-rest-spread', - }, + options: this.getOverrideWebpackRuleOptions( + { + presets: tsPresets, + // We don't need plugin-proposal-class-properties + // because taken care of by @wpackio/base + // '@babel/proposal-class-properties', + // We don't need object-rest-spread because it is + // already in stage-4 and taken care of by preset-env + // '@babel/proposal-object-rest-spread', + }, + this.config.tsBabelOverride + ), }, ], exclude: /(node_modules)/, @@ -399,4 +428,40 @@ ${bannerConfig.copyrightText}${bannerConfig.credit ? creditNote : ''}`, name: this.file.name, }; } + + /** + * Get final options for @wpackio/babel-preset-base, combining both + * system default and user defined value. + * + * @param defaults Default options for @wpackio/babel-preset-base. + * @param options User defined options for @wpackio/babel-preset-base. + */ + private getBabelPresetOptions( + defaults: PresetOptions, + options: PresetOptions | undefined + ): PresetOptions { + // If options is not undefined or null, then spread over it + if (options != null) { + return { ...defaults, ...options }; + } + return defaults; + } + + /** + * Get final loader option based on user and system. + * + * @param defaults Default options as calculated by system. + * @param override User defined option. + */ + private getOverrideWebpackRuleOptions( + defaults: webpack.RuleSetLoader['options'], + override: webpack.RuleSetLoader['options'] | undefined + ): webpack.RuleSetLoader['options'] { + // If override is not undefined or null, then return it + if (override != null) { + return override; + } + // Otherwise just return default + return defaults; + } } diff --git a/packages/scripts/src/config/project.config.default.ts b/packages/scripts/src/config/project.config.default.ts index badeeec95..248b9ac05 100644 --- a/packages/scripts/src/config/project.config.default.ts +++ b/packages/scripts/src/config/project.config.default.ts @@ -1,5 +1,7 @@ import webpack from 'webpack'; +import { PresetOptions } from '@wpackio/babel-preset-base/lib/preset'; + // Export common interfaces /** @@ -53,6 +55,17 @@ export interface ProjectConfig { outputPath: string; hasReact: boolean; hasSass: boolean; + hasFlow: boolean; + // If provided it is spread over whatever wpackio/scripts generates + jsBabelPresetOptions?: PresetOptions; + // If provided it is spread over whatever wpackio/scripts generates + tsBabelPresetOptions?: PresetOptions; + // Completely overrides `babel-loader` options for javascript files + // tslint:disable-next-line:no-any + jsBabelOverride?: string | { [x: string]: any }; + // Completely overrides `babel-loader` options for typescript files + // tslint:disable-next-line:no-any + tsBabelOverride?: string | { [x: string]: any }; externals?: webpack.Configuration['externals']; alias?: webpack.Resolve['alias']; errorOverlay?: boolean; @@ -102,6 +115,8 @@ export const projectConfigDefault: ProjectConfig = { hasReact: true, // Needs sass? hasSass: true, + // Needs flow? + hasFlow: false, // Externals externals: { jquery: 'jQuery', diff --git a/yarn.lock b/yarn.lock index c43afb54a..ad2f6910a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -282,6 +282,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-flow@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.0.0.tgz#70638aeaad9ee426bc532e51523cff8ff02f6f17" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-import-meta@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.0.0.tgz#ca946b73216c29c39a55ef2d739097fee8a85d69" @@ -391,6 +397,13 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-flow-strip-types@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.0.0.tgz#c40ced34c2783985d90d9f9ac77a13e6fb396a01" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.0.0" + "@babel/plugin-transform-for-of@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz#f2ba4eadb83bd17dc3c7e9b30f4707365e1c3e39" @@ -587,6 +600,13 @@ js-levenshtein "^1.1.3" semver "^5.3.0" +"@babel/preset-flow@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.0.0.tgz#afd764835d9535ec63d8c7d4caf1c06457263da2" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/preset-react@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.0.0.tgz#e86b4b3d99433c7b3e9e91747e2653958bc6b3c0"