From 4f2ee522f751fa93563557d3c684e618693fe4de Mon Sep 17 00:00:00 2001 From: KonpekiCode <512054675@qq.com> Date: Wed, 26 Jan 2022 10:04:21 +0800 Subject: [PATCH] feat: convert webpack entries (#85) * refactor: get webpack entry * refactor: webpack input transformer * feat: convert webpack entries * chore: clear import * chore: add comment and guard * fix: break out of loop --- src/generate/geneIndexHtml.ts | 120 +++++++++++--------- src/generate/geneViteConfig.ts | 8 +- src/transform/transformWebpack.ts | 11 +- tests/geneIndexHtml.test.ts | 55 ++++----- tests/testdata/index-html/webpack.config.js | 12 ++ 5 files changed, 113 insertions(+), 93 deletions(-) create mode 100644 tests/testdata/index-html/webpack.config.js diff --git a/src/generate/geneIndexHtml.ts b/src/generate/geneIndexHtml.ts index 9c06439..58d93a9 100644 --- a/src/generate/geneIndexHtml.ts +++ b/src/generate/geneIndexHtml.ts @@ -6,7 +6,7 @@ import type { Config } from '../config/config' import type { AstParsingResult } from '../ast-parse/astParse' import { TRANSFORMATION_TYPES } from '../constants/constants' import { recordConver } from '../utils/report' -import { parseVueCliConfig } from '../config/parse' +import { parseVueCliConfig, parseWebpackConfig } from '../config/parse' export async function geneIndexHtml ( rootDir: string, @@ -16,7 +16,7 @@ export async function geneIndexHtml ( const outputIndexPath: string = path.resolve(rootDir, 'index.html') const projectType: string = config.projectType - let entries: string[] = [] + let entries: Map = new Map() // `config.entry` can be type of string | array | object | function if ( config.entry && @@ -38,20 +38,25 @@ export async function geneIndexHtml ( recordConver({ num: 'B02', feat: 'add index.html' }) } -export function generateEntriesHtml (entries: string[]): string { - let entriesHtml: string = '' - for (const entry of entries) { - if (entry !== undefined) { - entriesHtml += ` \n` +export function generateHtmlWithEntries (entries: Map): string { + let htmlWithEntries: string = '' + Array.from(entries).every(record => { + const key = record[0] + const value = record[1] + if (key === 'app') { + value.forEach(entryPath => { + htmlWithEntries += ` \n` + }) + return false } - } - - return entriesHtml + return true + }) + return htmlWithEntries } export function generateWithVueCliPublicIndex ( astParsingResult: AstParsingResult, - entries: string[], + entries: Map, projectType: string ): string { let indexHtmlTransformationResult @@ -76,69 +81,72 @@ export function generateWithVueCliPublicIndex ( } else { indexHtmlContent = readSync(path.join(__dirname, '../template/index.html')) } - return stringFormat(indexHtmlContent, generateEntriesHtml(entries)) + return stringFormat(indexHtmlContent, generateHtmlWithEntries(entries)) } export async function getDefaultEntries ( rootDir: string, projectType: string -): Promise { - const entries: string[] = [] - // TODO: vue-cli pages config - if (projectType !== 'webpack') { - const vueConfigFile = path.resolve(rootDir, 'vue.config.js') - const vueConfig = await parseVueCliConfig(vueConfigFile) - const entryConfig = vueConfig.pages - if (entryConfig) { - Object.keys(entryConfig).forEach((key) => { - const entryPath: string = - Object.prototype.toString.call(entryConfig[key]) === '[object String]' - ? relativePathFormat(rootDir, entryConfig[key]) - : relativePathFormat(rootDir, entryConfig[key].entry) - entries.push(entryPath) - }) +): Promise> { + let entries: Map = new Map() + + // config entries + if (projectType === 'webpack' && fs.existsSync(path.resolve(rootDir, 'webpack.config.js'))) { + const webpackConfig = await parseWebpackConfig(path.resolve(rootDir, 'webpack.config.js')) + const webpackEntries = webpackConfig.entry + if (webpackEntries) { + entries = getEntries(rootDir, webpackEntries, webpackConfig.context) } - } - let mainFile = path.resolve(rootDir, 'src/main.ts') - if (fs.existsSync(mainFile)) { - if (!entries.some((entryPath) => entryPath === 'src/main.ts')) { - entries.push('/src/main.ts') + } else if (fs.existsSync(path.resolve(rootDir, 'vue.config.js'))) { + const vueConfig = await parseVueCliConfig(path.resolve(rootDir, 'vue.config.js')) + const vueEntries = vueConfig.pages + if (vueEntries) { + entries = getEntries(rootDir, vueEntries) } - return entries } - mainFile = path.resolve(rootDir, 'src/main.js') - if (fs.existsSync(mainFile)) { - if (!entries.some((entryPath) => entryPath === 'src/main.js')) { - entries.push('/src/main.js') + + // default + if (!entries.size) { + if (fs.existsSync(path.resolve(rootDir, 'src/main.ts'))) { + entries.set('app', ['/src/main.ts']) + } else if (fs.existsSync(path.resolve(rootDir, 'src/main.js'))) { + entries.set('app', ['/src/main.js']) } - return entries } + return entries } -export function getEntries (rootDir: string, entry: any): string[] { - let entries: string[] = [] - if (entry === undefined) { +export function getEntries (rootDir: string, rawEntry: any, context?: string): Map { + let entries: Map = new Map() + entries.set('app', []) + if (rawEntry === undefined) { return entries } - if (isObject(entry) || Array.isArray(entry)) { - Object.keys(entry).forEach(function (name) { - if (typeof entry[name] === 'string') { - entries.push(relativePathFormat(rootDir, entry[name])) - } else { - const deepEntries = getEntries(rootDir, entry[name]) - entries = entries.concat(deepEntries) - } + if (isObject(rawEntry)) { + Object.keys(rawEntry).forEach(name => { + const entry = isObject(rawEntry[name]) + ? rawEntry[name].import || rawEntry[name].entry + : rawEntry[name] + entries.set(name, getEntries(rootDir, entry, context).get('app')) }) - } - if (typeof entry === 'function') { - entries.push(entry()) - } - if (typeof entry === 'string') { - entries.push(relativePathFormat(rootDir, entry)) + } else if (typeof rawEntry === 'function') { + const entriesGettedByFunction = rawEntry() + entries = getEntries(rootDir, entriesGettedByFunction, context) + } else if (Array.isArray(rawEntry)) { + // set to 'app' by default + entries.set('app', rawEntry.map(entry => context ? relativePathFormat(rootDir, path.join(context, entry)) : relativePathFormat(rootDir, entry))) + } else if (typeof rawEntry === 'string') { + // set to 'app' by default + const entryPath = context + ? relativePathFormat(rootDir, path.join(context, rawEntry)) + : relativePathFormat(rootDir, rawEntry) + entries.set('app', [entryPath]) } // vite support hmr by default, so do not need to import webpack-hot-middleware - entries = entries.filter((item) => !item.includes('dev-client')) + entries.forEach((value, key) => { + entries.set(key, value.filter((item) => !item.includes('dev-client'))) + }) return entries } diff --git a/src/generate/geneViteConfig.ts b/src/generate/geneViteConfig.ts index dad4009..9d711c6 100644 --- a/src/generate/geneViteConfig.ts +++ b/src/generate/geneViteConfig.ts @@ -1,8 +1,8 @@ import path from 'path' -import { Config, TemplateData } from '../config/config' +import type { Config, TemplateData } from '../config/config' import { getTransformer } from '../transform/transformer' import { render, serializeObject } from './render' -import { AstParsingResult } from '../ast-parse/astParse' +import type { AstParsingResult } from '../ast-parse/astParse' export async function geneViteConfig (rootDir: string, outDir: string, config: Config, astParsingResult?: AstParsingResult): Promise { const template = path.resolve(__dirname, '../template/vite.config.ejs') @@ -13,10 +13,6 @@ export async function geneViteConfig (rootDir: string, outDir: string, config: C IMPORT_LIST: transformer.context.importers, USER_CONFIG: configStr } - // fill entry - if (config.entry === undefined) { - config.entry = transformer.context.config.build?.rollupOptions?.input - } render(outDir, template, data) } diff --git a/src/transform/transformWebpack.ts b/src/transform/transformWebpack.ts index e5b549b..68b765f 100644 --- a/src/transform/transformWebpack.ts +++ b/src/transform/transformWebpack.ts @@ -188,14 +188,15 @@ export class WebpackTransformer implements Transformer { function suitableFormat (entry: Entry) : Entry { const res : Entry = {} Object.keys(entry).forEach(function (name) { - if (!Array.isArray(entry[name])) { - res[name] = entry[name] + const entryPath = isObject(entry[name]) ? entry[name].import : entry[name] + if (!Array.isArray(entryPath)) { + res[name] = entryPath return } - entry[name].forEach((item, index) => { - const key = name.concat(index) + entryPath.forEach((item, index) => { + const key = name.concat(index.toString()) res[key] = item }) - }); + }) return res } diff --git a/tests/geneIndexHtml.test.ts b/tests/geneIndexHtml.test.ts index 0ebf6ff..7257094 100644 --- a/tests/geneIndexHtml.test.ts +++ b/tests/geneIndexHtml.test.ts @@ -1,12 +1,12 @@ import path from 'path' import { geneIndexHtml, - generateEntriesHtml, + generateHtmlWithEntries, generateWithVueCliPublicIndex, getDefaultEntries, getEntries } from '../src/generate/geneIndexHtml' -import { copyFileSync, mkdirSync, rmdirSync } from 'fs' +import { mkdirSync, rmdirSync } from 'fs' import { removeSync, writeSync, readSync } from '../src/utils/file' import { AstParsingResult } from '../src/ast-parse/astParse' import { TRANSFORMATION_TYPES } from '../src/constants/constants' @@ -133,7 +133,7 @@ describe('generateWithVueCliPublicIndex', () => { describe('getEntries', () => { test('getEntries from string', () => { const result = getEntries(path.resolve('tests/out-index-html'), './main.js') - expect(result).toEqual(['main.js']) + expect(result.get('app')).toEqual(['main.js']) }) test('getEntries from array', () => { @@ -141,7 +141,7 @@ describe('getEntries', () => { './app1.js', './app2.js' ]) - expect(result).toEqual(['app1.js', 'app2.js']) + expect(result.get('app')).toEqual(['app1.js', 'app2.js']) }) test('getEntries from object', () => { @@ -149,17 +149,12 @@ describe('getEntries', () => { app1: './app1.js', subPage1: ['./pages/sub1.js', './pages/sub2.js'], subPage2: { - a3: './pages/sub3.js', - a4: './pages/sub4.js' + import: './pages/sub3.js' } }) - expect(result).toEqual([ - 'app1.js', - 'pages/sub1.js', - 'pages/sub2.js', - 'pages/sub3.js', - 'pages/sub4.js' - ]) + expect(result.get('app1')).toEqual(['app1.js']) + expect(result.get('subPage1')).toEqual(['pages/sub1.js', 'pages/sub2.js']) + expect(result.get('subPage2')).toEqual(['pages/sub3.js']) }) test('getEntries from function', () => { @@ -167,28 +162,35 @@ describe('getEntries', () => { path.resolve('tests/out-index-html'), () => './main.js' ) - expect(result).toEqual(['./main.js']) + expect(result.get('app')).toEqual(['main.js']) }) test('getEntries contain webpack-hot-middleware', () => { const result = getEntries(path.resolve('tests/out-index-html'), { app: ['./build/dev-client', './app.js'] }) - expect(result).toEqual(['app.js']) + expect(result.get('app')).toEqual(['app.js']) }) }) describe('getDefaultEntries', () => { + test('getDefaultEntries from webpack.config.js', async () => { + const result = await getDefaultEntries( + path.resolve('tests/testdata/index-html'), + 'webpack' + ) + expect(result.get('app1')).toEqual(['pages/app1.js']) + expect(result.get('app2')).toEqual(['pages/app2.js', 'pages/app3.js']) + expect(result.get('app3')).toEqual(['pages/app4.js', 'pages/app5.js']) + }) + test('getDefaultEntries from vue.config.js', async () => { - const srcPath = path.resolve('tests/testdata/index-html/vue.config.js') - const destPath = path.resolve('tests/out-index-html/vue.config.js') - copyFileSync(srcPath, destPath) const result = await getDefaultEntries( - path.resolve('tests/out-index-html'), + path.resolve('tests/testdata/index-html'), 'vue-cli' ) - expect(result).toEqual(['pages/app1.js', 'pages/app2.js']) - removeSync(destPath) + expect(result.get('app1')).toEqual(['pages/app1.js']) + expect(result.get('app2')).toEqual(['pages/app2.js']) }) test('getDefaultEntries from src/main.ts', async () => { @@ -198,7 +200,7 @@ describe('getDefaultEntries', () => { path.resolve('tests/out-index-html'), 'vue-cli' ) - expect(result).toEqual(['/src/main.ts']) + expect(result.get('app')).toEqual(['/src/main.ts']) removeSync(filePath) }) @@ -209,14 +211,15 @@ describe('getDefaultEntries', () => { path.resolve('tests/out-index-html'), 'vue-cli' ) - expect(result).toEqual(['/src/main.js']) + expect(result.get('app')).toEqual(['/src/main.js']) removeSync(filePath) }) }) -test('generateEntriesHtml', () => { - const entries: string[] = ['pages/app1.js', 'pages/app2.js'] - const result: string = generateEntriesHtml(entries) +test('generateHtmlWithEntries', () => { + const entries: Map = new Map() + entries.set('app', ['pages/app1.js', 'pages/app2.js']) + const result: string = generateHtmlWithEntries(entries) expect(result).toBe( ' \n' + ' \n' diff --git a/tests/testdata/index-html/webpack.config.js b/tests/testdata/index-html/webpack.config.js new file mode 100644 index 0000000..849b555 --- /dev/null +++ b/tests/testdata/index-html/webpack.config.js @@ -0,0 +1,12 @@ +const path = require('path') + +module.exports = { + context: path.join(__dirname, 'pages'), + entry: { + app1: './app1.js', + app2: ['./app2.js', './app3.js'], + app3: { + import: ['./app4.js', './app5.js'] + } + } +}