UNPKG

koa-web-webpack

Version:
200 lines (179 loc) 4.92 kB
'use strict'; const fs = require("fs"); const webpack = require('webpack'); const webpackDev = require('webpack-dev-middleware'); const { VueLoaderPlugin } = require('vue-loader'); const path = require("path"); const crypto = require("crypto"); const thisPath = path.dirname(__filename); class App { // webpack解析 static webpacks = {}; static debug = true; static vuePath = thisPath + "/vue.js"; static cachePath = `${process.cwd()}/.cache/webpack/`; static cacheStr = fs.readFileSync(`${thisPath}/cache.js`).toString(); static async apply(middleware, req, res) { const _send = res.send; return new Promise((resolve, reject) => { try { res.send = function () { _send.apply(res, arguments) && resolve(false); }; middleware(req, res, resolve.bind(null, true)); } catch (error) { reject(error); } }); } /** * 删除文件夹 * @param {*} path */ static delDir(path) { let files = []; if (fs.existsSync(path)) { files = fs.readdirSync(path); files.forEach((file, index) => { let curPath = path + "/" + file; if (fs.statSync(curPath).isDirectory()) { App.delDir(curPath); } else { fs.unlinkSync(curPath); } }); fs.rmdirSync(path); } } /** * 创建文件夹 * @param {*} path * @returns */ static mkdir (path = '') { if (fs.existsSync(path)) { if (fs.statSync(path).isDirectory()) { return true; } } path = path.replace(/[\\]/g, "/"); let isWin = path[1] === ':'; let pos = path.lastIndexOf("/"); if (pos >= 0) { path = path.substring(0, pos); } let pathTmp = ""; let pathList = path.split("/"); if (isWin && pathList.length > 0) { pathTmp = pathList[0]; delete pathList.shift(); } try { for (const i in pathList) { pathTmp += "/" + pathList[i]; if (fs.existsSync(pathTmp)) { if (fs.statSync(pathTmp).isFile()) { return false; } } else { fs.mkdirSync(pathTmp); } } } catch (e) { return false; } return true; } /** * 获取webpack数据 * @param {*} rootPath * @param {*} subPath * @param {*} hd */ static async setWebpack(rootPath, subPath, hd) { if (App.webpacks[subPath] === undefined) { rootPath = rootPath.replace(/\\/g, '/'); let vueFile = `${rootPath}${subPath}.vue`; if (!(fs.existsSync(vueFile) && fs.statSync(vueFile).isFile())) { return; } let spMd5 = crypto.createHash('md5').update(subPath).digest("hex").substring(8, 24); let spCacheFile = `${App.cachePath}${spMd5}.js`; if (!App.mkdir(App.cachePath)) { return hd.ctx.body = "无法创建webpack缓存目录"; } let cacheStr = App.cacheStr.replace('__VUE__', `${rootPath}${subPath}.vue`); fs.writeFileSync(spCacheFile, cacheStr); let config = { entry: spCacheFile, mode: 'development', output: { filename: `${subPath}.js` }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', }, { test: /\.css$/, use: [ 'vue-style-loader', 'css-loader' ] }, { test: /\.scss$/, use: [ 'vue-style-loader', 'css-loader', 'sass-loader' ] }, { test: /\.js?$/, loader: 'babel-loader' } ] }, plugins: [ new VueLoaderPlugin() ], }; if (!App.debug) { // 启用调试 config['mode'] = 'production'; config['stats'] = 'errors-only'; } App.webpacks[subPath] = webpackDev(webpack(config), {}); } await App.apply(App.webpacks[subPath], hd.ctx.req, Object.assign(hd.ctx.res, { send: content => { return hd.ctx.body = content; } })); } static async run (setMid, setData, setLoad) { App.delDir(App.cachePath); setMid('js', async hd => { let hdData = hd.data; let subPath = hdData.ctxDir; if (hdData.domainPath !== '') { subPath = `${hdData.domainPath}/${subPath}`; } let hdPath = `${hdData.rootPath}${subPath}`; let wpPath = `${hdPath}.vue`; if (!fs.existsSync(wpPath) || !fs.statSync(wpPath).isFile()) { return; } await App.setWebpack(hdData.rootPath, subPath, hd); }); setLoad((koaApp, config) => { if (typeof config.webpackDebug === 'boolean') { App.debug = config.webpackDebug; } }); }; } module.exports = App.run;