UNPKG

@aomi/webapp-cli

Version:

a web app cli

367 lines (348 loc) 9.76 kB
import * as fs from 'fs'; import * as path from 'path'; import * as webpack from 'webpack'; import * as HtmlWebpackPlugin from 'html-webpack-plugin'; // import * as AddAssetHtmlPlugin from 'add-asset-html-webpack-plugin'; import * as MiniCssExtractPlugin from 'mini-css-extract-plugin'; import {getWebappConfig, WebappConfig} from '../utils/getWebappConfig'; const ESLintPlugin = require('eslint-webpack-plugin'); const FaviconsWebpackPlugin = require('favicons-webpack-plugin'); const {NODE_ENV = 'development'} = process.env; console.log(`NODE_ENV=${NODE_ENV}`); const DEBUG = NODE_ENV !== 'production'; const PROD = NODE_ENV === 'production'; const appHome = process.cwd(); console.log(`APP_HOME=${appHome}`); const srcDirs = path.join(appHome, 'src'); console.log(`SRC_HOME=${srcDirs}`); const buildDir = path.join(appHome, 'build', 'app'); const scriptDir = 'javascript'; const styleDir = 'stylesheets'; const imagesDir = 'images'; const fontDir = 'fonts'; const fileDir = 'files'; const nodeModuleDir = path.join(appHome, 'node_modules'); const userPkg: WebappConfig = getWebappConfig(); let enableHash = true; if (typeof userPkg.enableHash === 'boolean') { enableHash = userPkg.enableHash; } const dll = Object.keys(userPkg.dllEntry || {}); const assets = [{ // Glob to match all of the dll file filepath: path.resolve(appHome, 'build/dll/*.dll.js'), publicPath: `./${scriptDir}`, outputPath: scriptDir }]; const entry: any = {}; const plugins = []; if (userPkg.mulitApp) { console.log('多应用程序'); const appRoot = path.join(srcDirs, 'app'); const appSrcDirs = fs.readdirSync(appRoot); appSrcDirs.filter(item => { const info = fs.statSync(path.join(appRoot, item)); return info.isDirectory(); }).forEach(app => { let entryFile; if (fs.existsSync(path.join(appRoot, app, 'index.web.tsx'))) { entryFile = path.join(appRoot, app, 'index.web.tsx'); } else if (fs.existsSync(path.join(appRoot, app, 'index.web.ts'))) { entryFile = path.join(appRoot, app, 'index.web.ts'); } console.log(`${app}入口JS: ${entryFile}`); entry[app] = entryFile; const indexHtmljs = path.join(appRoot, app, 'index.html.js'); let template; if (fs.existsSync(indexHtmljs)) { template = indexHtmljs; } else { template = path.join(appRoot, app, 'index.html'); } console.log(`${app}入口html: ${template}`); plugins.push(new HtmlWebpackPlugin({ template, filename: `${app}.html`, debug: DEBUG, env: process.env, excludeChunks: appSrcDirs.filter(item => item !== app) })); }); } else if (typeof userPkg.enableHtmlWebpackPlugin === 'boolean' ? userPkg.enableHtmlWebpackPlugin : true) { console.log('单用程序'); entry.app = path.join(srcDirs, 'index.web.tsx'); plugins.push(new HtmlWebpackPlugin({ template: path.join(srcDirs, 'index.html.js'), debug: DEBUG, env: process.env })); } const faviconPng = path.join(srcDirs, 'assets', 'images', 'favicon.png'); const faviconJpg = path.join(srcDirs, 'assets', 'images', 'favicon.jpg'); const faviconSvg = path.join(srcDirs, 'assets', 'images', 'favicon.svg'); let favicon = null; if (fs.existsSync(faviconPng)) { favicon = faviconPng; } else if (fs.existsSync(faviconJpg)) { favicon = faviconJpg; } else if (fs.existsSync(faviconSvg)) { favicon = faviconSvg; } if (favicon) { console.log(`发现favicon: ${favicon}`); plugins.push(new FaviconsWebpackPlugin({ logo: favicon, outputPath: path.join(imagesDir, 'favicon'), publicPath: 'images', prefix: 'favicon/' })); } export default { entry: () => entry, output: { path: buildDir, filename: DEBUG || !enableHash ? `${scriptDir}/[name].bundle.js` : `${scriptDir}/[name]-[contenthash].bundle.js`, chunkFilename: DEBUG || !enableHash ? `${scriptDir}/[name].chunk.js` : `${scriptDir}/[name]-[contenthash].chunk.js` }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.css', '.less', '.sass', 'scss', '.png', '.jpg', '.jpeg'], alias: { '@': srcDirs }, modules: [ 'node_modules', nodeModuleDir ] }, resolveLoader: { modules: ['node_modules'] }, context: srcDirs, plugins: [ new webpack.DefinePlugin({ // 定义环境变量 'process.env.NODE_ENV': JSON.stringify(NODE_ENV) }), new ESLintPlugin({ extensions: ['ts', 'tsx'], fix: true, // 临时注释掉,有bug 导致dev server 启动卡死 // threads: true }), ...plugins, new MiniCssExtractPlugin({ filename: DEBUG || !enableHash ? `${styleDir}/[name].css` : `${styleDir}/[name].[fullhash].css`, chunkFilename: DEBUG || !enableHash ? `${styleDir}/[id].css` : `${styleDir}/[id].[fullhash].css`, ignoreOrder: true }), // moment 组件自行根据项目中的需求进行增加替换 // new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/), // new AddAssetHtmlPlugin(assets), ...dll.map(dllName => new webpack.DllReferencePlugin({ context: appHome, manifest: require(`${appHome}/build/dll/${dllName}.manifest.json`) })) ], module: { rules: [{ test: /\.(js|mjs|jsx|ts|tsx)$/, use: ['thread-loader', 'babel-loader'], include: srcDirs }, { test: /\.html$/, use: [{ loader: 'html-loader' }] }, { test: /\.md$/, use: [{ loader: 'html-loader' }, { loader: 'markdown-loader', options: { ...(userPkg.markedOptions || {}) } }] }, { test: /\.css$/, exclude: /\.module\.css$/i, use: [DEBUG ? 'style-loader' : { loader: MiniCssExtractPlugin.loader }, { loader: 'css-loader', options: { sourceMap: DEBUG, importLoaders: 1, url: true } }, { loader: 'postcss-loader', options: { sourceMap: DEBUG, postcssOptions: { plugins: [ 'postcss-preset-env' ] } } }] }, { // For CSS modules test: /\.module\.css$/i, use: [DEBUG ? 'style-loader' : { loader: MiniCssExtractPlugin.loader }, { loader: 'css-loader', options: { sourceMap: DEBUG, importLoaders: 1, modules: true, url: true } }, { loader: 'postcss-loader', options: { sourceMap: DEBUG, postcssOptions: { plugins: [ 'postcss-preset-env' ] } } }] }, { // For CSS modules test: /\.less$/, exclude: /\.module\.less$/i, use: [DEBUG ? 'style-loader' : { loader: MiniCssExtractPlugin.loader }, { loader: 'css-loader', options: { sourceMap: DEBUG, importLoaders: 1 } }, { loader: 'postcss-loader', options: { sourceMap: DEBUG, postcssOptions: { plugins: [ 'postcss-preset-env' ] } } }, { loader: 'less-loader', options: { sourceMap: DEBUG, lessOptions: { javascriptEnabled: true } } }] }, { // For CSS modules test: /\.module\.less$/i, use: [DEBUG ? 'style-loader' : { loader: MiniCssExtractPlugin.loader }, { loader: 'css-loader', options: { sourceMap: DEBUG, importLoaders: 1, modules: true } }, { loader: 'postcss-loader', options: { sourceMap: DEBUG, postcssOptions: { plugins: [ 'postcss-preset-env' ] } } }, { loader: 'less-loader', options: { sourceMap: DEBUG, lessOptions: { javascriptEnabled: true } } }] }, { test: /\.(sa|sc)ss$/, exclude: /\.module\.(sa|sc)ss$/i, use: [DEBUG ? 'style-loader' : { loader: MiniCssExtractPlugin.loader }, { loader: 'css-loader', options: { sourceMap: DEBUG, importLoaders: 1 } }, { loader: 'postcss-loader', options: { sourceMap: DEBUG, postcssOptions: { plugins: [ 'postcss-preset-env' ] } } }, { loader: 'sass-loader', options: {sourceMap: DEBUG} }] }, { test: /\.module\.(sa|sc|c)ss$/i, use: [DEBUG ? 'style-loader' : { loader: MiniCssExtractPlugin.loader }, { loader: 'css-loader', options: { sourceMap: DEBUG, importLoaders: 1, modules: true } }, { loader: 'postcss-loader', options: { sourceMap: DEBUG, postcssOptions: { plugins: [ 'postcss-preset-env' ] } } }, { loader: 'sass-loader', options: {sourceMap: DEBUG} }] }, { test: /\.(png|jpe?g|gif|svg|webp)$/i, type: 'asset', parser: { dataUrlCondition: { // 64 kb maxSize: 1024 * 64 } }, generator: { filename: `${imagesDir}/[name]-[hash][ext]` } }, { test: /\.(woff|eot|ttf)/, type: 'asset/resource', generator: { filename: `${fontDir}/[name]-[hash][ext]` } }, { test: /\.(xls|xlsx|doc|docx)/, type: 'asset/resource', generator: { filename: `${fileDir}/[name]-[hash][ext]` } }] } };