diff --git a/packages/generators/init-generator.ts b/packages/generators/init-generator.ts index 5230434d4c0..a40c0bc9d12 100644 --- a/packages/generators/init-generator.ts +++ b/packages/generators/init-generator.ts @@ -1,4 +1,3 @@ - import chalk from "chalk"; import * as logSymbols from "log-symbols"; import * as Generator from "yeoman-generator"; @@ -11,7 +10,7 @@ import { Confirm, Input, List } from "@webpack-cli/webpack-scaffold"; import { WebpackOptions } from "./types"; import entryQuestions from "./utils/entry"; import langQuestionHandler from "./utils/language"; -import styleQuestionHandler, { ILoader, StylingType } from "./utils/style"; +import styleQuestionHandler, { Loader, StylingType } from "./utils/style"; import tooltip from "./utils/tooltip"; /** @@ -55,8 +54,6 @@ export default class InitGenerator extends Generator { config: { configName: this.isProd ? "prod" : "config", topScope: [], - // TODO migrate tslint - // tslint:disable: object-literal-sort-keys webpackOptions: { mode: this.isProd ? "'production'" : "'development'", entry: undefined, @@ -66,7 +63,6 @@ export default class InitGenerator extends Generator { rules: [], }, }, - // tslint:enable: object-literal-sort-keys }, }; @@ -87,7 +83,7 @@ export default class InitGenerator extends Generator { ); } - this.configuration.config.webpackOptions.plugins.push( + (this.configuration.config.webpackOptions.plugins as string[]).push( "new webpack.ProgressPlugin()", ); @@ -134,7 +130,7 @@ export default class InitGenerator extends Generator { const done: () => {} = this.async(); const self: this = this; let regExpForStyles: string; - let ExtractUseProps: ILoader[]; + let ExtractUseProps: Loader[]; process.stdout.write( `\n${logSymbols.info}${chalk.blue(" INFO ")} ` + @@ -151,17 +147,17 @@ export default class InitGenerator extends Generator { ]) .then((multiEntriesAnswer: { multiEntries: boolean, - }) => + }): Promise<{}> => entryQuestions(self, multiEntriesAnswer.multiEntries), ) - .then((entryOption: object | string) => { + .then((entryOption: object | string): void => { if (typeof entryOption === "string" && entryOption.length > 0) { this.configuration.config.webpackOptions.entry = `${entryOption}`; } else if (typeof entryOption === "object") { this.configuration.config.webpackOptions.entry = entryOption; } }) - .then(() => + .then((): Promise<{}> => this.prompt([ Input( "outputDir", @@ -172,7 +168,7 @@ export default class InitGenerator extends Generator { ) .then((outputDirAnswer: { outputDir: string; - }) => { + }): void => { // As entry is not required anymore and we dont set it to be an empty string or """"" // it can be undefined so falsy check is enough (vs entry.length); if ( @@ -193,7 +189,7 @@ export default class InitGenerator extends Generator { `path.resolve(__dirname, '${outputDirAnswer.outputDir}')`; } }) - .then(() => + .then((): Promise<{}> => this.prompt([ List("langType", "Will you use one of the below JS solutions?", [ "ES6", @@ -203,11 +199,11 @@ export default class InitGenerator extends Generator { ]), ) .then((langTypeAnswer: { - langType: boolean; - }) => { + langType: string; + }): void => { langQuestionHandler(this, langTypeAnswer.langType); }) - .then(() => + .then((): Promise<{}> => this.prompt([ List("stylingType", "Will you use one of the below CSS solutions?", [ "No", @@ -219,10 +215,10 @@ export default class InitGenerator extends Generator { ])) .then((stylingTypeAnswer: { stylingType: string; - }) => - ({ ExtractUseProps, regExpForStyles } = styleQuestionHandler(self, stylingTypeAnswer.stylingType)), - ) - .then((): Promise => { + }): void => { + ({ ExtractUseProps, regExpForStyles } = styleQuestionHandler(self, stylingTypeAnswer.stylingType)); + }) + .then((): Promise<{}> | void => { if (this.isProd) { // Ask if the user wants to use extractPlugin return this.prompt([ @@ -235,7 +231,7 @@ export default class InitGenerator extends Generator { }) .then((useExtractPluginAnswer: { useExtractPlugin: string; - }) => { + }): void => { if (regExpForStyles) { if (this.isProd) { const cssBundleName: string = useExtractPluginAnswer.useExtractPlugin; @@ -246,12 +242,12 @@ export default class InitGenerator extends Generator { "\n", ); if (cssBundleName.length !== 0) { - this.configuration.config.webpackOptions.plugins.push( + (this.configuration.config.webpackOptions.plugins as string[]).push( // TODO: use [contenthash] after it is supported `new MiniCssExtractPlugin({ filename:'${cssBundleName}.[chunkhash].css' })`, ); } else { - this.configuration.config.webpackOptions.plugins.push( + (this.configuration.config.webpackOptions.plugins as string[]).push( "new MiniCssExtractPlugin({ filename:'style.css' })", ); } @@ -273,7 +269,7 @@ export default class InitGenerator extends Generator { }); } - public installPlugins() { + public installPlugins(): void { const packager = getPackageManager(); const opts: { dev?: boolean, @@ -292,7 +288,7 @@ export default class InitGenerator extends Generator { this.fs.extendJSON(this.destinationPath("package.json"), require(packageJsonTemplatePath)(this.isProd)); const entry = this.configuration.config.webpackOptions.entry; - const generateEntryFile = (entryPath: string, name: string) => { + const generateEntryFile = (entryPath: string, name: string): void => { entryPath = entryPath.replace(/'/g, ""); this.fs.copyTpl( path.resolve(__dirname, "./templates/index.js"), @@ -304,7 +300,7 @@ export default class InitGenerator extends Generator { if ( typeof entry === "string" ) { generateEntryFile(entry, "your main file!"); } else if (typeof entry === "object") { - Object.keys(entry).forEach((name) => + Object.keys(entry).forEach((name: string): void => generateEntryFile(entry[name], `${name} main file!`), ); } diff --git a/packages/generators/utils/entry.ts b/packages/generators/utils/entry.ts index 6feca520301..4e3798a2a29 100644 --- a/packages/generators/utils/entry.ts +++ b/packages/generators/utils/entry.ts @@ -16,7 +16,10 @@ interface CustomGenerator extends Generator { * @returns {Object} An Object that holds the answers given by the user, later used to scaffold */ -export default function entry(self: CustomGenerator, multiEntries: boolean): Promise<{}> { +export default function entry( + self: CustomGenerator, + multiEntries: boolean, +): Promise<{}> { let entryIdentifiers: string[]; let result: Promise<{}>; if (multiEntries) { @@ -26,8 +29,8 @@ export default function entry(self: CustomGenerator, multiEntries: boolean): Pro "multipleEntries", "How do you want to name your bundles? (separated by comma)", validate, - "pageOne, pageTwo", - ), + "pageOne, pageTwo" + ) ]) .then( (multipleEntriesAnswer: { multipleEntries: string }): Promise => { @@ -53,7 +56,7 @@ export default function entry(self: CustomGenerator, multiEntries: boolean): Pro !n[val].includes("path") && !n[val].includes("process") ) { - n[val] = `\'${n[val].replace(/"|'/g, "").concat(".js")}\'`; + n[val] = `\'./${n[val].replace(/"|'/g, "").concat(".js")}\'`; } webpackEntryPoint[val] = n[val]; } @@ -66,59 +69,37 @@ export default function entry(self: CustomGenerator, multiEntries: boolean): Pro ); }, Promise.resolve()); } + return forEachPromise( entryIdentifiers, (entryProp: string): Promise => self.prompt([ InputValidate( `${entryProp}`, - `What is the location of "${entryProp}"? [example: ./src/${entryProp}]`, - validate - ) - ]) - ).then( - (entryPropAnswer: object): object => { - Object.keys(entryPropAnswer).forEach( - (val: string): void => { - if ( - entryPropAnswer[val].charAt(0) !== "(" && - entryPropAnswer[val].charAt(0) !== "[" && - !entryPropAnswer[val].includes("function") && - !entryPropAnswer[val].includes("path") && - !entryPropAnswer[val].includes("process") - ) { - n[val] = `\'./${n[val].replace(/"|'/g, "").concat(".js")}\'`; + `What is the location of "${entryProp}"?`, + validate, + `src/${entryProp}`, + ), + ])) + .then( + (entryPropAnswer: object): object => { + Object.keys(entryPropAnswer).forEach( + (val: string): void => { + if ( + entryPropAnswer[val].charAt(0) !== "(" && + entryPropAnswer[val].charAt(0) !== "[" && + !entryPropAnswer[val].includes("function") && + !entryPropAnswer[val].includes("path") && + !entryPropAnswer[val].includes("process") + ) { + entryPropAnswer[val] = `\'./${entryPropAnswer[val].replace(/"|'/g, "").concat(".js")}\'`; + } + webpackEntryPoint[val] = entryPropAnswer[val]; } - webpackEntryPoint[val] = n[val]; - }); - } else { - n = {}; + ); + return webpackEntryPoint; } - return fn(trimmedProp); - }); - }, Promise.resolve()); - } - return forEachPromise(entryIdentifiers, (entryProp: string): Promise<{} | void> => - self.prompt([ - InputValidate( - `${entryProp}`, - `Which will be the entry point of "${entryProp}"?`, - validate, - `src/${entryProp}`, - ), - ]), - ).then((entryPropAnswer: object): object => { - Object.keys(entryPropAnswer).forEach((val: string): void => { - if ( - entryPropAnswer[val].charAt(0) !== "(" && - entryPropAnswer[val].charAt(0) !== "[" && - !entryPropAnswer[val].includes("function") && - !entryPropAnswer[val].includes("path") && - !entryPropAnswer[val].includes("process") - ) { - entryPropAnswer[val] = `\'./${entryPropAnswer[val].replace(/"|'/g, "").concat(".js")}\'`; - } - ); + ); } ); } else { @@ -128,15 +109,16 @@ export default function entry(self: CustomGenerator, multiEntries: boolean): Pro "singularEntry", "Which will be your application entry point?", "src/index", - ), + ) ]) - .then((singularEntryAnswer: { - singularEntry: string, - }): string => { - let { singularEntry } = singularEntryAnswer; - singularEntry = `\'./${singularEntry.replace(/"|'/g, "").concat(".js")}\'`; - if (singularEntry.length <= 0) { - self.usingDefaults = true; + .then( + (singularEntryAnswer: { singularEntry: string }): string => { + let { singularEntry } = singularEntryAnswer; + singularEntry = `\'./${singularEntry.replace(/"|'/g, "").concat(".js")}\'`; + if (singularEntry.length <= 0) { + self.usingDefaults = true; + } + return singularEntry; } ); } diff --git a/packages/generators/utils/language.ts b/packages/generators/utils/language.ts index a71f1b9f4b5..a722eeeff53 100644 --- a/packages/generators/utils/language.ts +++ b/packages/generators/utils/language.ts @@ -16,6 +16,20 @@ interface ModuleRule extends Object { type Preset = string | object; +function updateEntryExt(self, newExt: string): void { + const jsEntryOption = self.configuration.config.webpackOptions.entry; + const jsExtension = new RegExp("\.js(?!.*\.js)"); + let tsEntryOption = {}; + if (typeof jsEntryOption === "string") { + tsEntryOption = jsEntryOption.replace(jsExtension, newExt); + } else if (typeof jsEntryOption === "object") { + Object.keys(jsEntryOption).forEach((entry: string): void => { + tsEntryOption[entry] = jsEntryOption[entry].replace(jsExtension, newExt); + }); + } + self.configuration.config.webpackOptions.entry = tsEntryOption; +} + /** * * Returns an module.rule object that has the babel loader if invoked @@ -24,8 +38,6 @@ type Preset = string | object; */ export function getBabelLoader(): ModuleRule { return { - // TODO migrate tslint - // tslint:disable: object-literal-sort-keys test: "/\.js$/", include: ["path.resolve(__dirname, 'src')"], loader: "'babel-loader'", @@ -40,23 +52,19 @@ export function getBabelLoader(): ModuleRule { ] ] }, - // tslint:enable: object-literal-sort-keys }; } export function getTypescriptLoader(): ModuleRule { return { - // TODO migrate tslint - // tslint:disable: object-literal-sort-keys test: "/\.tsx?$/", loader: "'ts-loader'", include: ["path.resolve(__dirname, 'src')"], exclude: ["/node_modules/"], - // tslint:enable: object-literal-sort-keys }; } -export default function language(self, langType) { +export default function language(self, langType: string): void { switch (langType) { case LangType.ES6: self.dependencies.push( @@ -81,18 +89,7 @@ export default function language(self, langType) { extensions: [ "'.tsx'", "'.ts'", "'.js'" ], }; - // Update the entry files extensions to .ts - const jsEntryOption = self.configuration.config.webpackOptions.entry; - const jsExtension = new RegExp("\.js(?!.*\.js)"); - let tsEntryOption = {}; - if (typeof jsEntryOption === "string") { - tsEntryOption = jsEntryOption.replace(jsExtension, ".ts"); - } else if (typeof jsEntryOption === "object") { - Object.keys(jsEntryOption).forEach((entry) => { - tsEntryOption[entry] = jsEntryOption[entry].replace(jsExtension, ".ts"); - }); - } - self.configuration.config.webpackOptions.entry = tsEntryOption; + updateEntryExt(self, ".ts"); break; } } diff --git a/packages/generators/utils/style.ts b/packages/generators/utils/style.ts index cc07306d3c0..d05a5241a75 100644 --- a/packages/generators/utils/style.ts +++ b/packages/generators/utils/style.ts @@ -7,7 +7,7 @@ export enum StylingType { PostCSS = "PostCSS", } -export enum Loader { +export enum LoaderName { CSS = "css-loader", SASS = "sass-loader", STYLE = "style-loader", @@ -22,7 +22,7 @@ export enum StyleRegex { PostCSS = "/\.css$/", } -export interface ILoader { +export interface Loader { loader: string; options?: { importLoaders?: number; @@ -31,29 +31,32 @@ export interface ILoader { }; } -export default function style(self, stylingType) { - const ExtractUseProps: ILoader[] = []; - let regExpForStyles = null; +export default function style(self, stylingType: string): { + ExtractUseProps: Loader[], + regExpForStyles: StyleRegex, +} { + const ExtractUseProps: Loader[] = []; + let regExpForStyles: StyleRegex = null; switch (stylingType) { case StylingType.CSS: regExpForStyles = StyleRegex.CSS; self.dependencies.push( - Loader.CSS, + LoaderName.CSS, ); if (!self.isProd) { self.dependencies.push( - Loader.STYLE, + LoaderName.STYLE, ); ExtractUseProps.push( { - loader: `"${Loader.STYLE}"`, + loader: `"${LoaderName.STYLE}"`, }, ); } ExtractUseProps.push({ - loader: `"${Loader.CSS}"`, + loader: `"${LoaderName.CSS}"`, options: { sourceMap: true, }, @@ -65,28 +68,28 @@ export default function style(self, stylingType) { self.dependencies.push( "node-sass", - Loader.SASS, - Loader.CSS, + LoaderName.SASS, + LoaderName.CSS, ); if (!self.isProd) { self.dependencies.push( - Loader.STYLE, + LoaderName.STYLE, ); ExtractUseProps.push( { - loader: `"${Loader.STYLE}"`, + loader: `"${LoaderName.STYLE}"`, }, ); } ExtractUseProps.push( { - loader: `"${Loader.CSS}"`, + loader: `"${LoaderName.CSS}"`, options: { sourceMap: true, }, }, { - loader: `"${Loader.SASS}"`, + loader: `"${LoaderName.SASS}"`, options: { sourceMap: true, }, @@ -99,28 +102,28 @@ export default function style(self, stylingType) { self.dependencies.push( "less", - Loader.LESS, - Loader.CSS, + LoaderName.LESS, + LoaderName.CSS, ); if (!self.isProd) { self.dependencies.push( - Loader.STYLE, + LoaderName.STYLE, ); ExtractUseProps.push( { - loader: `"${Loader.STYLE}"`, + loader: `"${LoaderName.STYLE}"`, }, ); } ExtractUseProps.push( { - loader: `"${Loader.CSS}"`, + loader: `"${LoaderName.CSS}"`, options: { sourceMap: true, }, }, { - loader: `"${Loader.LESS}"`, + loader: `"${LoaderName.LESS}"`, options: { sourceMap: true, }, @@ -141,29 +144,29 @@ export default function style(self, stylingType) { self.dependencies.push( "precss", "autoprefixer", - Loader.CSS, - Loader.POSTCSS, + LoaderName.CSS, + LoaderName.POSTCSS, ); if (!self.isProd) { self.dependencies.push( - Loader.STYLE, + LoaderName.STYLE, ); ExtractUseProps.push( { - loader: `"${Loader.STYLE}"`, + loader: `"${LoaderName.STYLE}"`, }, ); } ExtractUseProps.push( { - loader: `"${Loader.CSS}"`, + loader: `"${LoaderName.CSS}"`, options: { importLoaders: 1, sourceMap: true, }, }, { - loader: `"${Loader.POSTCSS}"`, + loader: `"${LoaderName.POSTCSS}"`, options: { plugins: `function () { return [ diff --git a/packages/utils/scaffold.ts b/packages/utils/scaffold.ts index 3fc8bf20c0f..7f0eb1acd48 100644 --- a/packages/utils/scaffold.ts +++ b/packages/utils/scaffold.ts @@ -70,30 +70,26 @@ export default function runTransform(transformConfig: TransformConfig, action: s return astTransform(j, ast, f, config[f] as any, transformAction); } return astTransform(j, ast, f, config.webpackOptions[f], transformAction); - } - ) - .then( - (): void | PromiseLike => { - let configurationName: string; - if (!config.configName) { - configurationName = "webpack.config.js"; - } else { - configurationName = "webpack." + config.configName + ".js"; - } - - const projectRoot = findProjectRoot(); - const outputPath: string = initActionNotDefined - ? transformConfig.configPath - : path.join(projectRoot || process.cwd(), configurationName); - const source: string = ast.toSource({ - quote: "single", + }) + .then((): void | PromiseLike => { + let configurationName: string; + if (!config.configName) { + configurationName = "webpack.config.js"; + } else { + configurationName = "webpack." + config.configName + ".js"; + } + const projectRoot = findProjectRoot(); + const outputPath: string = initActionNotDefined + ? transformConfig.configPath + : path.join(projectRoot || process.cwd(), configurationName); + const source: string = ast.toSource({ + quote: "single", + }); + runPrettier(outputPath, source); + }) + .catch((err: Error): void => { + console.error(err.message ? err.message : err); }); - runPrettier(outputPath, source); - - }) - .catch((err: IError) => { - console.error(err.message ? err.message : err); - }); }); let successMessage: string = chalk.green(`Congratulations! Your new webpack configuration file has been created!\n\n`) +