webpack 由单入口改成多入口打包

最近有需求说需要单独的页面露出提供给斗鱼等第三方页面,spa这种还需要启服务。故将原来的单入口改成了多入口打包,修改如下。

一.生产环境的webpack配置修改

1.首先需要获取到入口的文件,由于webpack对异步有特殊写法要求,这里我用了glob这个库去获取container目录下所有的文件

const getEntrys = () => {
  // 获取container下的所有文件目录
  let globPath = 'src/container/**/index.js'
  let files = glob.sync(globPath)
  let containers = []
  for (let i = 0; i < files.length; i++) {
    const direname = path.dirname(files[i])
    containers.push(direname.replace('src/container/', ''))
  }
  return containers
}

2. 配置webpack多入口 entry

const addEntry = () => {
  let entryObj = {}
  entrys.forEach(item => {
    entryObj[item.toLowerCase()] = [path.resolve(__dirname, '..', `src/container/${item}/render.js`)]
  })
  entryObj.vendor = ['react', 'react-dom']
  return entryObj
}

3.配置webpack 多个HtmlWebpackPlugin

entrys.forEach(pathname => {
  pathname = pathname.toLowerCase()
  let conf = {
    filename: `${pathname}.html`,
    template: path.resolve(__dirname, '..', 'src/index.html'),
    chunks: [pathname, 'vendor'],
    minify: {
      removeComments: true,
      collapseWhitespace: true,
    },
  }
  plugins.push(new HtmlWebpackPlugin(conf))
})

二. Container目录下新添加render.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './index'

const app = document.getElementById('app')

const render = Component => {
  ReactDOM.render(<Component />, app)
}

render(App)

这样的话就可以实现多入口打包了,为了开发方便我添加了一个container目录模板

/**
 * 创建容器
 */
const fs = require('fs')
const fse = require('fs-extra')
const path = require('path')

const cwd = process.cwd()
const ContainerName = process.argv[2]

if (ContainerName) {
  if (/^[A-Z][a-zA-Z0-9-]*$/.test(ContainerName)) {
    createContainer(ContainerName)
      .then(res => {
        console.log('容器文件创建成功')
      })
      .catch(err => {
        console.error(err)
      })
  } else {
    console.error('容器名称必须大写字母开头')
  }
} else {
  console.error('请添加容器名称,以大写字母开头 例如: npm run ctc Test')
}

/**
 * 创建文件夹
 * @param  {string}   dirName [文件夹路径]
 * @return {Promise}
 */
function mkdir(dirName) {
  return new Promise((resolve, reject) => {
    fs.exists(dirName, exists => {
      if (exists) {
        reject('创建失败,文件夹已存在')
      } else {
        fse
          .ensureDir(dirName)
          .then(() => {
            resolve()
          })
          .catch(err => {
            reject(err)
          })
      }
    })
  })
}

/**
 * 创建容器文件
 * @param  {string} ContainerName 容器名称
 * @return {Promise}
 */
function createContainer(ContainerName) {
  const _root = path.join(cwd, 'src', 'container', ContainerName)
  const containerTemp = getContainerTemp(ContainerName)
  const styleTemp = getStyleTemp(ContainerName)
  const renderTemp = getRenderTemp()
  return mkdir(_root)
    .then(() => fse.outputFile(path.join(_root, 'index.js'), containerTemp))
    .then(() => fse.outputFile(path.join(_root, 'render.js'), renderTemp))
    .then(() => fse.outputFile(path.join(_root, 'style.less'), styleTemp))
}

function getContainerTemp(ContainerName) {
  const _cn = ContainerName.toLocaleLowerCase()
  return `import React, { Component } from 'react'
import '../../less/normal.less'
import './style.less'

export default class ${ContainerName} extends Component {
  state={}

  componentDidMount() {}

  render() {
    return (
      <div className="${_cn}">
      </div>
    )
  }
}
    `
}

function getStyleTemp(ContainerName) {
  const _cn = ContainerName.toLocaleLowerCase()
  return `.${_cn} {}    `
}

function getRenderTemp() {
  return `import React from 'react'
import ReactDOM from 'react-dom'
import App from './index'

const app = document.getElementById('app')

const render = Component => {
  ReactDOM.render(<Component />, app)
}

render(App)`
}

完整的模板项目地址:https://github.com/lyxverycool/react-csr-multiple-templete

posted @ 2019-12-16 19:05  李元夕cool  阅读(396)  评论(0编辑  收藏  举报