UNPKG

chameleon-tool

Version:

chameleon 脚手架工具

306 lines (282 loc) 9.78 kB
const path = require('path'); const webpack = require('webpack'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const ProgressBarPlugin = require('progress-bar-webpack-plugin'); const {getBabelPath, getExcludeBabelPath, getGlobalCheckWhiteList, getFreePort, addCahceLoader} = require('./utils'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin') var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') const ChameleonWebpackPlugin = require('chameleon-webpack-plugin') const WebpackCheckPlugin = require('webpack-check-plugin') const config = require('./config.js'); const ChameleonErrorsWebpackPlugin = require('chameleon-errors-webpack-plugin'); const fs = require('fs'); const cmlUtils = require('chameleon-tool-utils'); const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin'); const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin'); const CircularDependencyPlugin = require('circular-dependency-plugin'); module.exports = function (options) { let { type, media, root } = options; function getstaticPath(filetype) { let staticPath = `static/${filetype}/[name]_[hash:7].[ext]`; if (options.staticPath) { staticPath = options.staticPath + staticPath; } return staticPath; } let webServerPort = getFreePort().webServerPort; let publicPath; let defaultPublichPathMap = { 'wx': `http://${config.ip}:${webServerPort}/wx/`, 'qq': `http://${config.ip}:${webServerPort}/qq/`, 'tt': `http://${config.ip}:${webServerPort}/tt/`, 'alipay': `http://${config.ip}:${webServerPort}/alipay/`, 'baidu': `http://${config.ip}:${webServerPort}/baidu/`, // baidu小程序的publicPath不能设置能/ 所以在启动dev服务的时候 也将dist作为静态资源 'web': `http://${config.ip}:${webServerPort}/`, 'weex': `http://${config.ip}:${webServerPort}/weex/` } publicPath = options.publicPath || defaultPublichPathMap[type]; if (!publicPath) { publicPath = `http://${config.ip}:${webServerPort}/${type}/` } let chameleonConfig = cml.config.get(); let commonConfig = { stats: cml.logLevel === 'debug' ? 'verbose' : 'none', output: { publicPath: publicPath }, resolve: { symlinks: false, extensions: ['.cml', '.interface', '.vue', '.js'], alias: { '$CMLPROJECT': path.resolve(cml.root), '/components': path.resolve(cml.projectRoot, 'src/components'), '$PROJECT': path.resolve(root), '$ROUTER_CONFIG': path.resolve(root, './src/router.config.json') }, modules: [ 'node_modules', path.join(cml.root, '/node_modules') ] }, resolveLoader: { modules: [ path.join(cml.root, '/node_modules'), 'node_modules' ] }, module: { rules: [{ test: path.resolve(root, 'node_modules/chameleon-runtime/.temp/router.js'), loader: path.join(__dirname, 'routerLoader.js') }, { test: /\.js$/, exclude: getExcludeBabelPath(), // 不能babel babel-runtime include: getBabelPath(), use: [{ loader: 'babel-loader', options: { 'filename': path.join(cml.root, 'chameleon.js') } }] }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'chameleon-url-loader', options: { limit: false, // 不做limit的base64转换,需要添加?inline参数 name: getstaticPath('img'), outputPath: function(output) { // 处理图片中的@符号 改成_ 解决在支付宝小程序中上传失败的问题 output = cml.utils.handleSpecialChar(output) return output; } } }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: 'file-loader', options: { name: getstaticPath('media'), outputPath: function(output) { // 处理图片中的@符号 改成_ 解决在支付宝小程序中上传失败的问题 output = cml.utils.handleSpecialChar(output) return output; } } }, { test: /\.(woff|woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'file-loader', options: { name: getstaticPath('fonts'), outputPath: function(output) { // 处理图片中的@符号 改成_ 解决在支付宝小程序中上传失败的问题 output = cml.utils.handleSpecialChar(output) return output; } } }, { test: /\.interface$/, // exclude: /(node_modules|bower_components)/, // 不能babel babel-runtime include: getBabelPath(), use: [{ loader: 'babel-loader', options: { 'filename': path.join(cml.root, 'chameleon.js') } }, { loader: 'interface-loader', options: { cmlType: type, media, check: chameleonConfig.check } } ] } ] }, plugins: [ new webpack.DefinePlugin({ 'process.env.platform': JSON.stringify(type) }), new ChameleonErrorsWebpackPlugin({ cmlType: type, showWarning: chameleonConfig.optimize && chameleonConfig.optimize.showWarning }) ] } if (options.cache) { addCahceLoader(commonConfig, type); } if (chameleonConfig.enableGlobalCheck === true) { commonConfig.plugins.push( new WebpackCheckPlugin({ cmlType: type, whiteListFile: getGlobalCheckWhiteList() }) ) } if (chameleonConfig.optimize && chameleonConfig.optimize.processBar) { commonConfig.plugins.push(new ProgressBarPlugin()) } if (chameleonConfig.optimize && chameleonConfig.optimize.circularDependency) { commonConfig.plugins.push(new ProgressBarPlugin()) } if (options.definePlugin) { commonConfig.plugins.push(new webpack.DefinePlugin(options.definePlugin)) } if (options.analysis) { commonConfig.plugins.push(new BundleAnalyzerPlugin()) } let devApiPrefix = `http://${config.ip}:${webServerPort}` // 兼容旧版api let apiPrefix = options.apiPrefix || devApiPrefix; // 新版api 优先读取domain // 浅拷贝不影响config中的domain let domain = {}; if (options.domain) { domain = { ...options.domain } } if (options.media === 'dev') { // dev模式添加domainKey参数 Object.keys(domain).forEach(key => { if (domain[key].toLowerCase() === 'localhost') { domain[key] = devApiPrefix; } domain[key] = domain[key] + '__DEV_SPLIT__' + key; }) commonConfig.plugins.push( new ExtraWatchWebpackPlugin({ dirs: [path.join(cml.projectRoot, 'mock/api')] }) ); commonConfig.plugins.push( new DuplicatePackageCheckerPlugin({ verbose: true }) ); commonConfig.plugins.push( new DuplicatePackageCheckerPlugin({ verbose: true }) ); if (chameleonConfig.optimize && chameleonConfig.optimize.circularDependency) { commonConfig.plugins.push( new CircularDependencyPlugin({ // exclude detection of files based on a RegExp exclude: /node_modules/, // include specific files based on a RegExp include: /src/, // add errors to webpack instead of warnings failOnError: true, // allow import cycles that include an asyncronous import, // e.g. via import(/* webpackMode: "weak" */ './file.js') allowAsyncCycles: false, // set the current working directory for displaying module paths cwd: process.cwd() }) ); } } // 兼容旧版api commonConfig.plugins.push(new webpack.DefinePlugin({ 'process.env.cmlApiPrefix': JSON.stringify(apiPrefix) })) Object.keys(domain).forEach(key => { commonConfig.plugins.push(new webpack.DefinePlugin({ ['process.env.domain.' + key]: JSON.stringify(domain[key]) })) }) commonConfig.plugins.push(new webpack.DefinePlugin({ 'process.env.media': JSON.stringify(options.media) })) if (options.minimize) { commonConfig.plugins = commonConfig.plugins.concat([ new OptimizeCSSPlugin({ assetNameRegExp: /\.css$/, cssProcessorOptions: { safe: true, discardComments: { removeAll: true }, autoprefixer: false } }), new UglifyJsPlugin({ compress: { drop_console: chameleonConfig.optimize && chameleonConfig.optimize.dropConsole } }) ]) } let moduleIdType = options.moduleIdType let moduleIdMap = { hash: new webpack.HashedModuleIdsPlugin(), name: new webpack.NamedModulesPlugin(), chameleon: new ChameleonWebpackPlugin({openModuleHash: true, openChunkHash: true}) } if (moduleIdType && moduleIdMap[moduleIdType]) { commonConfig.plugins.push(moduleIdMap[moduleIdType]) } let subProject = chameleonConfig.subProject; if (subProject && subProject.length > 0) { subProject.forEach(item => { let npmName = cmlUtils.isString(item) ? item : item.npmName; let packageJSON = JSON.parse(fs.readFileSync(path.resolve(cml.projectRoot, 'node_modules', npmName, 'package.json'), {encoding: 'utf-8'})); let cmlConfig = packageJSON.cml || {}; let definePlugin = cmlConfig.definePlugin; if (definePlugin) { Object.keys(definePlugin).forEach(key => { definePlugin[key] = JSON.stringify(definePlugin[key]) }) commonConfig.plugins.push(new webpack.DefinePlugin(definePlugin)) } }) } return commonConfig; }