koot
Version:
Koot.js - React isomorphic framework created by CMUX
346 lines (316 loc) • 11.5 kB
JavaScript
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
// const ExtractTextPlugin = require("extract-text-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const defaultDefines = require('../../defaults/defines.js')
const getPathnameProjectConfigFile = require('../../utils/get-pathname-project-config-file')
// 打包结果目录
const outputPath = 'dist'
// 执行顺序,从右到左
const factory = async ({
aliases,
env = process.env.WEBPACK_BUILD_ENV,
stage = process.env.WEBPACK_BUILD_STAGE,
// spa = false,
defines = {},
}) => {
const useSpCssLoader = 'sp-css-loader?length=8&mode=replace'
const useUniversalAliasLoader = {
loader: "universal-alias-loader",
options: {
alias: aliases
}
}
const extractCSS = (
env === 'prod' ||
(env === 'dev' && stage === 'client')
) ? true : false
let rulesJS = [
{
test: /\.(js|jsx)$/,
use: [
{
loader: 'babel-loader',
// options: {
// cacheDirectory: true
// }
}
]
}
]
if (env === 'dev' && stage === 'client') {
rulesJS.push({
test: /\.jsx$/,
use: [
require.resolve('./loaders/react-hot'),
]
})
}
return {
module: {
rules: [
// {
// test: /\.json$/,
// loader: 'json-loader'
// },
// CSS - general
{
test: /\.css$/,
exclude: [/\.g\.css$/, /node_modules/],
use: [
useSpCssLoader,
"postcss-loader",
useUniversalAliasLoader
]
}, {
test: /\.less$/,
exclude: [/\.g\.less$/, /node_modules/],
use: [
useSpCssLoader,
"postcss-loader",
"less-loader",
useUniversalAliasLoader
]
}, {
test: /\.scss$/,
exclude: [/\.g\.scss$/, /node_modules/],
use: [
useSpCssLoader,
"postcss-loader",
"sass-loader",
useUniversalAliasLoader
]
},
// CSS - in node_modules
{
test: /\.css$/,
include: /node_modules/,
use: [
"style-loader",
"postcss-loader"
]
}, {
test: /\.less$/,
include: /node_modules/,
use: [
"style-loader",
"postcss-loader",
"less-loader"
]
}, {
test: /\.scss$/,
include: /node_modules/,
use: [
"style-loader",
"postcss-loader",
"sass-loader"
]
},
// CSS - critical
{
test: extractCSS ? /critical\.g\.css$/ : /^IMPOSSIBLE$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
useUniversalAliasLoader
]
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: ["css-loader", "postcss-loader"]
// })
}, {
test: extractCSS ? /critical\.g\.less$/ : /^IMPOSSIBLE$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"less-loader",
useUniversalAliasLoader
]
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: ["css-loader", "postcss-loader", "less-loader"]
// })
}, {
test: extractCSS ? /critical\.g\.scss$/ : /^IMPOSSIBLE$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
useUniversalAliasLoader
]
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: ["css-loader", "postcss-loader", "sass-loader"]
// })
},
// CSS - other global
{
test: /\.g\.css$/,
exclude: extractCSS ? /critical\.g\.css$/ : undefined,
// loader: 'style-loader!postcss-loader'
use: [
"style-loader",
"css-loader",
"postcss-loader",
useUniversalAliasLoader
]
}, {
test: /\.g\.less$/,
exclude: extractCSS ? /critical\.g\.less$/ : undefined,
// loader: 'style-loader!postcss-loader!less-loader'
use: [
"style-loader",
"css-loader",
"postcss-loader",
"less-loader",
useUniversalAliasLoader
]
}, {
test: /\.g\.scss$/,
exclude: extractCSS ? /critical\.g\.scss$/ : undefined,
// loader: 'style-loader!postcss-loader!sass-loader'
use: [
"style-loader",
"css-loader",
"postcss-loader",
"sass-loader",
useUniversalAliasLoader
]
},
//
...rulesJS
]
},
resolve: {
alias: { ...aliases },
modules: [
'__modules',
'node_modules'
],
extensions: ['.js', '.jsx', '.json', '.css', '.less', '.sass', '.scss']
},
plugins: plugins(env, stage, defines)
}
}
// 执行顺序, 先 -> 后
const plugins = (env, stage, defines = {}) => {
const defaults = {}
Object.keys(defaultDefines).forEach(key => {
defaults[key] = JSON.stringify(defaultDefines[key])
})
let g = Object.assign(
defaults,
{
__CLIENT__: stage == 'client',
__SERVER__: stage == 'server',
__DEV__: env == 'dev',
__PROD__: env == 'prod',
// '__SPA__': !!spa,
// __DIST__: JSON.stringify(process.env.KOOT_DIST_DIR),
// 将 SERVER_PORT 赋值
// 服务器启动时,会优先选取当前环境变量中的 SERVER_PORT,如果没有,会选择 __SERVER_PORT__
__SERVER_PORT__: JSON.stringify(process.env.SERVER_PORT),
// __KOOT_PROJECT_CONFIG_PATHNAME__: getPathnameProjectConfigFile(),
},
defines
)
if (env == 'prod') {
process.env.NODE_ENV = 'production'
// g['process.env'] = {
// 'NODE_ENV': JSON.stringify('production')
// }
}
const envs = [
'KOOT_DIST_DIR',
'KOOT_I18N',
'KOOT_I18N_TYPE',
"KOOT_I18N_LOCALES",
"KOOT_I18N_COOKIE_KEY",
"KOOT_I18N_COOKIE_DOMAIN",
"KOOT_HTML_TEMPLATE",
"KOOT_PWA_AUTO_REGISTER",
"KOOT_PWA_PATHNAME",
"WEBPACK_BUILD_TYPE",
"WEBPACK_BUILD_ENV",
"WEBPACK_CHUNKMAP",
// "WEBPACK_SERVER_PUBLIC_PATH",
]
const envsToDefine = envs.filter(key => (
typeof process.env[key] !== 'undefined'
))
for (let key in g) {
if (typeof g[key] === 'function')
g[key] = g[key]()
}
return [
new webpack.DefinePlugin(g),
new webpack.EnvironmentPlugin(envsToDefine),
// new webpack.ContextReplacementPlugin(
// /^__KOOT_PROJECT_CONFIG_PATHNAME__$/,
// (context) => {
// const a = Object.assign(context, {
// regExp: /^\.\/\w+/,
// request: getPathnameProjectConfigFile()
// })
// console.log(a)
// }
// ),
new webpack.NormalModuleReplacementPlugin(
/^__KOOT_PROJECT_CONFIG_PATHNAME__$/,
getPathnameProjectConfigFile()
)
]
}
const resolve = Object.assign({
modules: [
'__modules',
'node_modules'
],
alias: {
// Apps: path.resolve(appPath, './apps'),
// "@app": path.resolve(appPath, './apps/app')
},
extensions: ['.js', '.jsx', '.json', '.css', '.less', '.sass', '.scss']
})
// 这里配置需要babel处理的node_modules
// 大部分是自己用es6语法写的模块
const needBabelHandleList = [
'koot',
]
// https://github.com/webpack/webpack/issues/2852
// webpack 在打包服务端依赖 node_modules 的时候易出错,
// 所以把 package.json 里描述的依赖过滤掉,只打包自己写的代码
// 注:在上线的时候需要需要自行安装 package.json 的依赖包
const filterExternalsModules = () => {
const externals = []
.concat(fs.readdirSync(path.resolve(__dirname, '../../../')))
.concat(fs.readdirSync(path.resolve(process.cwd(), 'node_modules')))
.concat(['react-dom/server'])
.filter((x) => ['.bin'].concat(needBabelHandleList).indexOf(x) === -1)
.filter((x) => !/^sp-/.test(x))
.filter((x) => !/^super-/.test(x))
.filter((x) => !/^koot-/.test(x))
.filter((x) => !/^@/.test(x))
.reduce((ext, mod) => {
ext[mod] = ['commonjs', mod].join(' ') // eslint-disable-line no-param-reassign
// ext[mod] = mod + '' // eslint-disable-line no-param-reassign
return ext
}, {})
externals['@babel/register'] = ['commonjs', '@babel/register'].join(' ')
// externals['@babel/polyfill'] = '@babel/polyfill'
return externals
}
// 已下属都可以在 /config/webpack.js 中扩展
module.exports = {
factory,
outputPath,
// rules,
plugins,
resolve,
needBabelHandleList,
filterExternalsModules
}