Skip to content

Commit

Permalink
feat: convert webpack entries (#85)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
konpeki622 committed Jan 26, 2022
1 parent d23a0ed commit 4f2ee52
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 93 deletions.
120 changes: 64 additions & 56 deletions src/generate/geneIndexHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<string, string[]> = new Map()
// `config.entry` can be type of string | array | object | function
if (
config.entry &&
Expand All @@ -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 += ` <script type="module" src="${entry}"></script>\n`
export function generateHtmlWithEntries (entries: Map<string, string[]>): string {
let htmlWithEntries: string = ''
Array.from(entries).every(record => {
const key = record[0]
const value = record[1]
if (key === 'app') {
value.forEach(entryPath => {
htmlWithEntries += ` <script type="module" src="${entryPath}"></script>\n`
})
return false
}
}

return entriesHtml
return true
})
return htmlWithEntries
}

export function generateWithVueCliPublicIndex (
astParsingResult: AstParsingResult,
entries: string[],
entries: Map<string, string[]>,
projectType: string
): string {
let indexHtmlTransformationResult
Expand All @@ -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<string[]> {
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<Map<string, string[]>> {
let entries: Map<string, string[]> = 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<string, string[]> {
let entries: Map<string, string[]> = 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
}
8 changes: 2 additions & 6 deletions src/generate/geneViteConfig.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
const template = path.resolve(__dirname, '../template/vite.config.ejs')
Expand All @@ -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)
}
11 changes: 6 additions & 5 deletions src/transform/transformWebpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
55 changes: 29 additions & 26 deletions tests/geneIndexHtml.test.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -133,62 +133,64 @@ 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', () => {
const result = getEntries(path.resolve('tests/out-index-html'), [
'./app1.js',
'./app2.js'
])
expect(result).toEqual(['app1.js', 'app2.js'])
expect(result.get('app')).toEqual(['app1.js', 'app2.js'])
})

test('getEntries from object', () => {
const result = getEntries(path.resolve('tests/out-index-html'), {
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', () => {
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 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 () => {
Expand All @@ -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)
})

Expand All @@ -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<string, string[]> = new Map()
entries.set('app', ['pages/app1.js', 'pages/app2.js'])
const result: string = generateHtmlWithEntries(entries)
expect(result).toBe(
' <script type="module" src="pages/app1.js"></script>\n' +
' <script type="module" src="pages/app2.js"></script>\n'
Expand Down
12 changes: 12 additions & 0 deletions tests/testdata/index-html/webpack.config.js
Original file line number Diff line number Diff line change
@@ -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']
}
}
}

0 comments on commit 4f2ee52

Please sign in to comment.