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