UNPKG

1.1.0

Version:

full stack typescript

367 lines (366 loc) 16.1 kB
const path = require("path"); const fs = require("fs"); const globby = require("globby"); const merge = require("lodash.merge"); const fileExists = require('file-exists'); const nodeExternals = require('webpack-node-externals'); const webpack = require('webpack'); const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin; const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin'); const DefinePlugin = require('webpack/lib/DefinePlugin'); const rimraf = require("rimraf"); const mkdirp = require("mkdirp"); const gulp = require("gulp"); const webpackDevServer = require("webpack-dev-server"); const ts = require('gulp-typescript'); const babel = require('gulp-babel'); module.exports = { isObjectStr: function(str) { try { let res = JSON.parse(str); return res; } catch (e) { return false; } }, copy: function() { let me = this; const obj = {}; return globby([path.join(__dirname, 'copy/**'), path.join(__dirname, 'copy/.**'), "!" + path.join(__dirname, 'copy')]) .then((paths) => { paths.forEach((filepath, index) => { let stat = fs.statSync(filepath); if (stat.isFile()) { let extname = path.extname(filepath); let targetpath = path.join(process.cwd(), path.basename(filepath)); let content = (extname == ".js" || extname == ".json") ? require(filepath) : fs.readFileSync(filepath).toString(); let iftargetExists = fileExists.sync(targetpath); let targetContent = (extname == ".js" || extname == ".json") ? (iftargetExists ? require(targetpath) : {}) : (iftargetExists ? fs.readFileSync(targetpath).toString() : ""); let contentObj = (extname == ".js" || extname == ".json") ? content : me.isObjectStr(content); let targetObj = (extname == ".js" || extname == ".json") ? targetContent : me.isObjectStr(targetContent); if ((!!contentObj && !!targetObj) || (!iftargetExists && !!contentObj)) { let _contnet = iftargetExists ? merge(targetObj, contentObj) : contentObj; obj[targetpath] = { value: _contnet, isObj: true, isJs: extname == ".js" }; } else { obj[targetpath] = { value: content, isObj: false, isJs: extname == ".js" }; } } }); return obj; }); }, init() { let me = this; const path = require("path"); return me.copy().then((obj) => { // 根据配置建立目录 return obj; }) }, // 构建前端代码 buildFront(programpath, useserver, port, host) { let me = this; if (!programpath) { console.log("没有指定模块"); return; } else { let result = me.analyseProgramPath(programpath, 1); let webpackConfig = me.initFrontConfig(result); if (useserver || webpackConfig.hasOwnProperty("devServer")) { let server = webpackConfig.devServer || {}; let serverConfig = merge({ hot: true, inline: true, host: host || "localhost", port: port || 8899, stats: { colors: true } }, server); for (let entry in webpackConfig.entry) { webpackConfig.entry[entry] = [webpackConfig.entry[entry]]; webpackConfig.entry[entry].unshift(`webpack-dev-server/client?http://${serverConfig.host}:${serverConfig.port}`, "webpack/hot/dev-server") }; webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()) let devServer = new webpackDevServer(webpack(webpackConfig), serverConfig); devServer.listen(serverConfig.port, serverConfig.host, function() { console.log(`服务器已启动: http://${serverConfig.host}:${serverConfig.port}`) }) } else { // 首先清空目标 rimraf.sync(path.join(result.dest)); webpack(webpackConfig, function(err, stat) { // rimraf(path.join(result.entry, "tsconfig.json"), () => {}) if (err) console.log(err); console.log(stat.toString({ chunks: true, colors: true })) }) }; } }, // 构建后端代码 buildEnd(programpath) { let me = this; if (!programpath) { console.log("没有指定模块"); return; } else { let result = me.analyseProgramPath(programpath, 0); me.compileEnd(result.entry, result.dest); } }, // 0 end 1 front analyseProgramPath(programpath, type) { let rootConfigPath = path.join(process.cwd(), "fst.config.js") if (fileExists.sync(rootConfigPath)) { let rootConfig = require(rootConfigPath); let srcType = path.join(process.cwd(), path.join(rootConfig.src, type == 1 ? rootConfig.front : rootConfig.end)); let destType = path.join(process.cwd(), path.join(rootConfig.dest, type == 1 ? rootConfig.front : rootConfig.end)); let programEntry = path.join(srcType, programpath); let programDest = path.join(destType, programpath); let programConfigPath = path.join(programEntry, "fst.config.js"); let programRootConfig = (rootConfig.hasOwnProperty("programs") && rootConfig.programs.hasOwnProperty(programpath)) ? (type == 1 ? rootConfig.programs[programpath].front : rootConfig.programs[programpath].end) : {}; let programConfig = merge(programRootConfig, fileExists.sync(programConfigPath) ? require(programConfigPath) : {}); return { entry: programEntry, dest: programDest, config: programConfig } } else { console.error(`${rootConfigPath}不存在`); return null; } }, initFrontConfig(result) { let me = this; let IS_PROD = process.env.FST_ENV === "production"; let webpackConfig = { entry: {}, plugins: [], resolve: { extensions: ['.ts', ".js"] }, output: { path: path.join(result.dest), filename: '[name][hash].js' }, module: { rules: [{ test: /\.json$/, use: 'json-loader' }, { test: /\.html$/, use: 'raw-loader', // exclude: [helpers.root('src/index.html')] }, { test: /\.(jpg|png|gif)$/, use: 'file-loader' }, { test: /\.(eot|woff2?|svg|ttf)([\?]?.*)$/, use: 'file-loader' }] } }; // 配置入口 result.config.entry = result.config.hasOwnProperty("entry") ? result.config.entry : [{ src: "polyfills.ts", name: "polyfills" }, { src: "main.ts", name: "main" }]; let entry_quene = []; result.config.entry.forEach((entry, index) => { entry_quene.push(entry.name); const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); webpackConfig.entry[entry.name] = path.join(result.entry, entry.src); webpackConfig.plugins.push(new CommonsChunkPlugin({ name: entry.name, chunks: [entry.name] })) }); webpackConfig.plugins.push(new CommonsChunkPlugin({ name: entry_quene.reverse() })); // 初始化tsconfig.js let rootTsconfigPath = path.join(process.cwd(), "tsconfig.json"); let rootTsconfig = fileExists.sync(rootTsconfigPath) ? require(rootTsconfigPath) : {}; if (!result.config.hasOwnProperty("tsconfig")) { result.config.tsconfig = {}; } result.config.tsconfig = merge(rootTsconfig, result.config.tsconfig); // 是否使用babel result.config.useBabel = result.config.useBabel == undefined ? true : result.config.useBabel; let tempTsconfigPath = path.join(result.entry, "tsconfig.json"); fs.writeFileSync(tempTsconfigPath, JSON.stringify(result.config.tsconfig), "utf8"); webpackConfig.module.rules.push({ test: /\.ts(x?)$/, loader: 'awesome-typescript-loader', query: { useBabel: result.config.useBabel, useCache: true, configFileName: "tsconfig.json" } }); // 配置服务器 result.config.server = merge({ enable: false, config: { port: 8899, host: "localhost", inline: true, disableHostCheck: true, hot: true, historyApiFallback: true, watchOptions: { aggregateTimeout: 300, poll: 1000 } } }, result.config.hasOwnProperty("server") ? result.config.server : {}); if (result.config.server.enable) { webpackConfig.devServer = result.config.server.config; } // 配置node result.config.node = me.mergeProperty(result.config, "node", { global: true, crypto: 'empty', process: true, module: false, clearImmediate: false, setImmediate: false }); webpackConfig.node = result.config.node; // 压缩的配置 result.config.uglify = me.mergeProperty(result.config, "uglify", { enable: IS_PROD, compress: { warnings: false, drop_console: IS_PROD } }); result.config.uglify.enable && webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin(merge({ compress: { warnings: false, drop_console: IS_PROD }, }, result.config.uglify))); // 抽取css extractcss result.config.extractcss = me.mergeProperty(result.config, "extractcss", { enable: IS_PROD }); if (result.config.extractcss.enable) { webpackConfig.module.rules.push({ test: /\.css$/, loader: ExtractTextPlugin.extract({ use: 'css-loader' }) }); webpackConfig.module.rules.push({ test: /\.less$/, loader: ExtractTextPlugin.extract({ use: 'css-loader!sass-loader' }) }); webpackConfig.module.rules.push({ test: /\.scss$/, loader: ExtractTextPlugin.extract({ use: 'css-loader!less-loader' }) }); webpackConfig.plugins.push(new ExtractTextPlugin('[name].[contenthash].css')); } else { webpackConfig.module.rules.push({ test: /\.css$/, use: 'style-loader!css-loader' }); webpackConfig.module.rules.push({ test: /\.less$/, use: 'style-loader!css-loader!less-loader' }); webpackConfig.module.rules.push({ test: /\.scss$/, use: 'style-loader!css-loade!sass-loaderr' }) } // 配置HTML // webpackonfig.html result.config.html = me.mergeProperty(result.config, "html", { template: path.join(result.entry, "index.html"), // title: "", chunksSortMode: 'dependency', // metadata: METADATA, inject: 'head' }) webpackConfig.plugins.push(new HtmlWebpackPlugin(result.config.html)) // 配置script加载方法 result.config.script = me.mergeProperty(result.config, "script", { defaultAttribute: 'defer' }); webpackConfig.plugins.push(new ScriptExtHtmlWebpackPlugin(result.config.script)) // 变量设置 result.config.variable = me.mergeProperty(result.config, "variable", {}); webpackConfig.plugins.push(new DefinePlugin(result.config.variable)); // 手动扩展 result.config.extend = result.config.extend || function(c) { return c; }; webpackConfig = result.config.extend(webpackConfig); return webpackConfig; }, initFrontModule(names) { let fstConfig = require(path.join(process.cwd(), "fst.config.js")); let src = path.join(process.cwd(), fstConfig.src); names.forEach((module, index) => { let modulepath = path.join(src, path.join("front", module)); // fs.writeFileSync(path.join) mkdirp.sync(modulepath); fs.writeFileSync(path.join(modulepath, "main.ts"), '"use strict"', 'utf8'); fs.writeFileSync(path.join(modulepath, "polyfills.ts"), '"use strict"', 'utf8'); fs.writeFileSync(path.join(modulepath, "style.less"), 'body {}', 'utf8'); let html = `<!DOCTYPE html><html><head></head><body>Hello World!</body></html> ` fs.writeFileSync(path.join(modulepath, "index.html"), html, 'utf8'); fs.writeFileSync(path.join(modulepath, "fst.config.js"), `module.exports = {}`, 'utf8'); fs.writeFileSync(path.join(modulepath, "package.json"), '{}', 'utf8'); }) }, initEndModule(names) { let fstConfig = require(path.join(process.cwd(), "fst.config.js")); let src = path.join(process.cwd(), fstConfig.src); names.forEach((module, index) => { let modulepath = path.join(src, path.join("end", module)); // fs.writeFileSync(path.join) mkdirp.sync(modulepath); fs.writeFileSync(path.join(modulepath, "main.ts"), '"use strict"', 'utf8'); fs.writeFileSync(path.join(modulepath, "fst.config.js"), `module.exports = {}`, 'utf8'); fs.writeFileSync(path.join(modulepath, "package.json"), '{}', 'utf8'); }) }, mergeProperty(obj, key, begin) { return merge(begin, obj.hasOwnProperty(key) ? obj[key] : {}); }, compileEnd(dest, output) { let _dest = path.join(dest, "**/**.ts"); // const tsProject = ts.createProject('tsconfig.json'); let rootTsconfig = require(path.join(process.cwd(), "tsconfig.json")); // let destFstConfig = require(path) let destFstConfigPath = path.join(dest, "fst.config.js"); let destTsconfig = fileExists(destFstConfigPath) ? require(destFstConfigPath).tsconfig : {}; let config = merge(rootTsconfig, destTsconfig); rimraf.sync(output); let stream = gulp.src([_dest, "!node_modules/**/**"]).pipe(ts(config.compilerOptions)); stream .pipe(gulp.dest(output)); } }