@iam-com/snack-scripts 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # 1.0.0
2
+ 基于产品2.3.7
package/bin/main.js ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // Makes the script crash on unhandled rejections instead of silently
4
+ // ignoring them. In the future, promise rejections that are not handled will
5
+ // terminate the Node.js process with a non-zero exit code.
6
+ const {spawn} = require('child_process');
7
+ const path = require('path');
8
+ const minimist = require('minimist');
9
+ const fs = require('fs-extra');
10
+ const {version} = require('../package.json');
11
+ const {GetPackageList} = require(path.resolve(__dirname, '../utils/package'));
12
+ // 解析命令行参数
13
+ const args = process.argv.slice(2);
14
+ const argv = minimist(args, {
15
+ default: {
16
+ project: null
17
+ }
18
+ });
19
+ const scriptIndex = args.findIndex(
20
+ x => x === 'build' || x === 'start' || x === 'entry'
21
+ );
22
+
23
+ // 命令行参数
24
+ const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
25
+ // 项目路径
26
+ let projectPath = argv.project || process.cwd();
27
+ // 模版自定义路径
28
+ let templatePath = argv.templatePath ? path.resolve(projectPath, argv.templatePath) : path.resolve(__dirname, '../template');
29
+ /** webpack配置路径 **/
30
+ // snack模块打包配置
31
+ const snackPath = path.resolve(__dirname, `../config/webpack.snack.config.js`);
32
+ // snack模块独立html入口
33
+ const indexHTMLPath = path.resolve(__dirname, `../config/webpack.index.config.js`);
34
+ // sanck模块加载器
35
+ const loaderConfigPath = path.resolve(__dirname, `../config/webpack.loader.config.js`);
36
+ // 开发调试webpack配置
37
+ const devConfigPath = path.resolve(__dirname, `../config/webpack.dev.config.js`);
38
+ // 独立页面打包配置
39
+ const entryConfigPath = path.resolve(__dirname, `../config/webpack.entry.config.js`);
40
+ //
41
+ const platform = process.platform;
42
+ let webpackFile = 'webpack';
43
+ if (platform === 'win32')
44
+ webpackFile = 'webpack.cmd';
45
+
46
+ async function run(script) {
47
+ let argv = [];
48
+ let argvEntry = [];
49
+ let argvLoader = [];
50
+ let argvDev = [];
51
+ switch (script) {
52
+ case 'start':
53
+ argvDev = ['serve', '--mode=development', `--config=${devConfigPath}`];
54
+ // 运行模式
55
+ process.env.RUN_MODE = 'development';
56
+ break;
57
+ case 'build':
58
+ argv = ['--mode=production', `--config=${snackPath}`];
59
+ argvEntry = ['--mode=production', `--config=${indexHTMLPath}`];
60
+ argvLoader = ['--mode=production', `--config=${loaderConfigPath}`];
61
+ // 运行模式
62
+ process.env.RUN_MODE = 'production';
63
+ break;
64
+ case 'entry':
65
+ argv = ['--mode=production', `--config=${entryConfigPath}`];
66
+ // 运行模式
67
+ process.env.RUN_MODE = 'production';
68
+ break;
69
+ }
70
+ const projectPackageJSON = fs.readJSONSync(path.resolve(projectPath, 'package.json'));
71
+ if (projectPackageJSON.name === 'snack-cli') {
72
+ throw '请修改 snack-cli package.json "name" 的默认名称,该名称将在部署时作为分类目录';
73
+ }
74
+ // 脚手架版本
75
+ process.env.SNACK_CLI_VERSION = version;
76
+ // 运行命令
77
+ process.env.RUN_SCRIPT = script;
78
+ // snack-scripts 目录
79
+ process.env.SNACK_SCRIPTS_PATH = __dirname;
80
+ // 公共资源目录
81
+ process.env.PROJECT_COMMON_NAME = '__common__';
82
+ // 打包项目package.json
83
+ process.env.PROJECT_PACKAGE_JSON = JSON.stringify(projectPackageJSON);
84
+ // 项目分类
85
+ process.env.PROJECT_TYPE = projectPackageJSON.name;
86
+ // 打包项目绝对路径
87
+ process.env.PROJECT_PATH = projectPath;
88
+ // 打包项目sanck模块绝对路径
89
+ process.env.PROJECT_PACKAGE_PATH = path.resolve(projectPath, projectPackageJSON.input || 'src/package');
90
+ // 临时目录
91
+ process.env.PROJECT_TEMP_PATH = path.resolve(projectPath, '.snack');
92
+ // 模版目录
93
+ process.env.PROJECT_TEMPLATE_PATH = path.join(process.env.PROJECT_TEMP_PATH, 'template');
94
+ await fs.remove(process.env.PROJECT_TEMPLATE_PATH);
95
+ // 复制模版目录到临时目录
96
+ const err = await fs.copy(templatePath, process.env.PROJECT_TEMPLATE_PATH);
97
+ if (err) {
98
+ console.error('临时目录创建失败');
99
+ throw err;
100
+ }
101
+ // snack 配置
102
+ process.env.PROJECT_SNACK_CONFIG = JSON.stringify(projectPackageJSON.snack || {});
103
+ if (script === 'entry') {
104
+ if (!projectPackageJSON.snack && !projectPackageJSON.snack.entry) throw 'package.json 未找到snack.entry配置项';
105
+ /**
106
+ * id string 页面id
107
+ * type string 页面分类(可选)
108
+ * service string snackbar服务端地址,默认当前地址栏(可选),
109
+ * devServer string 调试服务网关(可选),
110
+ * favicon string 角标图标,项目相对路径(可选),
111
+ *
112
+ */
113
+ // 打包项目输出路径
114
+ process.env.PROJECT_OUT_PATH = path.resolve(projectPath, projectPackageJSON.snack.entry.name || 'entry');
115
+ console.log('create entry ...');
116
+ await execWebpack(argv);
117
+ } else {
118
+ // 打包项目输出路径
119
+ if (process.env.RUN_MODE === 'development') // 开发模式
120
+ process.env.PROJECT_OUT_PATH = path.resolve(process.env.PROJECT_TEMP_PATH, 'temp');
121
+ else // 生产模式
122
+ process.env.PROJECT_OUT_PATH = path.resolve(projectPath, projectPackageJSON.output || 'dist', projectPackageJSON.name);
123
+ // 打包项目模块目录扫描列表
124
+ process.env.PROJECT_PACKAGE_LIST = JSON.stringify(GetPackageList(process.env.PROJECT_PACKAGE_PATH));
125
+ console.log(`clear output dir "${process.env.PROJECT_OUT_PATH}" ...`);
126
+ clearOutput(process.env.PROJECT_OUT_PATH);
127
+ console.log('clear output dir end');
128
+ if (script === 'start') {
129
+ console.log('Snack DevServer Runing...');
130
+ await execWebpack(argvDev);
131
+ } else { // production
132
+ console.log('create loader.js ...');
133
+ await execWebpack(argvLoader);
134
+ console.log('create loader.jS end');
135
+ console.log('create entry HTML ...');
136
+ await execWebpack(argvEntry);
137
+ console.log('create entry HTML end');
138
+ console.log('create snack ...');
139
+ await execWebpack(argv);
140
+ console.log('create snack end');
141
+ }
142
+ if (process.env.RUN_MODE !== 'development' && !await check(process.env.PROJECT_OUT_PATH)) {
143
+ fs.removeSync(process.env.PROJECT_OUT_PATH);
144
+ throw '完整性校验失败';
145
+ }
146
+ }
147
+ console.log(`
148
+ _____ __ ________ ____
149
+ / ___/____ ____ ______/ /__ / ____/ / / _/
150
+ \\__ \\/ __ \\/ __ \`/ ___/ //_/ / / / / / /
151
+ ___/ / / / / /_/ / /__/ ,< / /___/ /____/ /
152
+ /____/_/ /_/\\__,_/\\___/_/|_| \\____/_____/___/ v.${version}
153
+ `);
154
+ }
155
+
156
+ /**
157
+ * 校验打包完整性
158
+ * @param output
159
+ * @return {Promise<boolean>}
160
+ */
161
+ async function check(output) {
162
+ try {
163
+ const list = await fs.readdir(output);
164
+ for (let i = 0, l = list.length; i < l; i++) {
165
+ const dirname = list[i];
166
+ if (dirname === '__common__') continue;
167
+ const snackjson = path.join(output, dirname, 'snack.json');
168
+ if (!await fs.exists(snackjson)) continue;
169
+ const index = path.join(output, dirname, 'index.js');
170
+ const ex = await fs.exists(index);
171
+ if (!ex) {
172
+ console.error('snack check: ', index, ' file is missing');
173
+ return false;
174
+ }
175
+ }
176
+ } catch (err) {
177
+ console.error('snack check: ', err);
178
+ return false;
179
+ }
180
+ console.log('完整性校验通过');
181
+ return true;
182
+ };
183
+
184
+ /**
185
+ * 执行webpack
186
+ * @param args
187
+ * @return {Promise<unknown>}
188
+ */
189
+ let isNpm = fs.existsSync(path.resolve(process.cwd(), './node_modules/.bin/', webpackFile));
190
+
191
+ function execWebpack(args) {
192
+ return new Promise(resolve => {
193
+ let ps = isNpm ? spawn(
194
+ 'webpack',
195
+ args,
196
+ {
197
+ stdio: 'inherit',
198
+ shell: true
199
+ }
200
+ ) : spawn(
201
+ path.resolve(__dirname, '../node_modules/.bin/', webpackFile),
202
+ args,
203
+ {
204
+ stdio: 'inherit'
205
+ }
206
+ );
207
+ ps.on('error', (e) => {
208
+ console.log(e);
209
+ resolve(false);
210
+ });
211
+ ps.on('exit', () => {
212
+ resolve(true);
213
+ });
214
+ });
215
+ }
216
+
217
+ /**
218
+ * 清理输出目录
219
+ * @param output 输出目录路径
220
+ */
221
+ function clearOutput(output) {
222
+ fs.removeSync(output);
223
+ }
224
+
225
+ run(script);
@@ -0,0 +1,183 @@
1
+ /**
2
+ * @author 刘佳
3
+ * @date 2022/1/20 10:18 下午
4
+ * @description snack开发调试入口页面
5
+ */
6
+
7
+ const path = require('path');
8
+ const fs = require('fs-extra');
9
+ const minimist = require('minimist');
10
+ const TerserPlugin = require('terser-webpack-plugin');
11
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
12
+ const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
13
+ const webpack = require('webpack');
14
+ const {VueLoaderPlugin} = require('vue-loader');
15
+ const {version} = require('../package.json');
16
+ const {injectIndexFile} = require('../utils/package');
17
+ // 获取命令行参数
18
+ let argv = minimist(process.argv.slice(2), {
19
+ default: {
20
+ mode: 'development'
21
+ }
22
+ });
23
+ // build mode
24
+ const isDevelopment = argv.mode === 'development';
25
+ const isProduction = argv.mode ? argv.mode === 'production' : true;
26
+ const packageJson = JSON.parse(process.env.PROJECT_PACKAGE_JSON);
27
+ const snackConfig = JSON.parse(process.env.PROJECT_SNACK_CONFIG);
28
+ const entryConfig = snackConfig.entry;
29
+
30
+ // paths
31
+ const outPath = process.env.PROJECT_OUT_PATH;
32
+ // add entry
33
+ let templatePath = path.resolve(process.env.PROJECT_TEMPLATE_PATH, 'dev');
34
+ const templatePkgPath = entryConfig && entryConfig.template && entryConfig.template.dev ? path.resolve(process.env.PROJECT_PATH, entryConfig.template.dev) : ''
35
+ // 注入外部js/css
36
+ injectIndexFile(templatePath, (indexRunFile) => {
37
+ // 导入模块列表
38
+ const packageList = JSON.parse(process.env.PROJECT_PACKAGE_LIST);
39
+ // add import
40
+ const imports = ['// Snack Module Start'];
41
+ const snackModuleMaps = [], snackModuleMapsParams = [];
42
+ const importModules = [];
43
+ for (let i = 0, l = packageList.length; i < l; i++) {
44
+ const item = packageList[i];
45
+ imports.push(`import * as ${item.name} from 'package/${item.dirName}'`);
46
+ snackModuleMaps.push(`${item.name}: {index:${item.name}.${item.dirName},setting:${item.name}.${item.dirName}Setting}`);
47
+ snackModuleMapsParams.push(item.name);
48
+ importModules.push(`'${item.name}': mosuleMaps['${item.name}'].index`);
49
+ importModules.push(`'${item.name}setting': mosuleMaps['${item.name}'].setting`);
50
+ }
51
+ imports.push('// Snack Module End');
52
+ // 替换文本
53
+ indexRunFile = indexRunFile.replace('/** import snack modules **/', imports.join('\n'));
54
+ indexRunFile = indexRunFile.replace('/** snack scripts version **/', version);
55
+ indexRunFile = indexRunFile.replace('/** snack module maps **/', `
56
+ const mosuleMaps = new Function('${snackModuleMapsParams.join('\',\'')}', \`return {
57
+ ${snackModuleMaps.join(',\n')}
58
+ }\`)(${snackModuleMapsParams.join(',')})
59
+ `);
60
+ indexRunFile = indexRunFile.replace('/** snack module maps **/', snackModuleMaps.join(',\n'));
61
+ indexRunFile = indexRunFile.replace('/** vers projectpkg **/', process.env.PROJECT_PACKAGE_JSON);
62
+ indexRunFile = indexRunFile.replace('/** vers packages **/', process.env.PROJECT_PACKAGE_LIST);
63
+ // 预导入模块
64
+ indexRunFile = indexRunFile.replace('/** vers importmodule **/', `
65
+ '${packageJson.name}': {
66
+ ${importModules.join(',\n')}
67
+ }
68
+ `);
69
+ return indexRunFile;
70
+ });
71
+ // 克隆临时目录
72
+ fs.copySync(templatePath, path.join(process.env.PROJECT_TEMP_PATH, 'temp/dev'));
73
+ templatePath = path.join(process.env.PROJECT_TEMP_PATH, 'temp/dev');
74
+
75
+ let conf = {
76
+ mode: 'development',
77
+ target: 'web',
78
+ devtool: 'eval-cheap-module-source-map',
79
+ entry: {
80
+ index: path.join(templatePath, 'index.tsx')
81
+ },
82
+ output: {
83
+ filename: `[name].bundle.[contenthash].js`,
84
+ path: outPath,
85
+ publicPath: '/',
86
+ assetModuleFilename: 'asset/[contenthash][ext][query]'
87
+ },
88
+ plugins: [
89
+ new HtmlWebpackPlugin({template: templatePkgPath || path.join(templatePath, 'index.html')}),
90
+ new VueLoaderPlugin(),
91
+ new webpack.HotModuleReplacementPlugin(),
92
+ new ReactRefreshWebpackPlugin()
93
+ ],
94
+ // loader配置
95
+ module: {
96
+ rules: [
97
+ {
98
+ test: /\.(ts|tsx|js|jsx|jsc|cjs)?$/,
99
+ loader: 'swc-loader',
100
+ options: {
101
+ jsc: {
102
+ parser: {
103
+ syntax: 'typescript',
104
+ tsx: true,
105
+ dynamicImport: true
106
+ },
107
+ target: 'es5',
108
+ keepClassNames: true,
109
+ transform: {
110
+ react: {
111
+ development: true,
112
+ refresh: true
113
+ }
114
+ }
115
+ }
116
+ }
117
+ },
118
+ {
119
+ test: /\.vue$/,
120
+ exclude: /node_modules/,
121
+ use: 'vue-loader'
122
+ },
123
+ // 样式loader
124
+ {
125
+ test: /\.(css|sass|scss)$/,
126
+ // 使用哪些loader进行处理
127
+ use: [
128
+ // use数组中loader执行顺序:从右到左,从下到上,依次执行(先执行css-loader)
129
+ // style-loader:创建style标签,将js中的样式资源插入进去,添加到head中生效
130
+ 'style-loader',
131
+ // css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串
132
+ 'css-loader',
133
+ // less-loader:将less文件编译成css文件,需要下载less-loader和less
134
+ 'sass-loader'
135
+ ]
136
+ },
137
+ {
138
+ exclude: [/\.(js|mjs|jsx|ts|tsx|vue|sass|scss|css|vue|html|json|cjs)$/],
139
+ type: 'asset/resource'
140
+ }
141
+ ]
142
+ },
143
+ resolve: {
144
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
145
+ alias: {
146
+ 'src': path.join(process.env.PROJECT_PATH, 'src'),
147
+ 'components': path.join(process.env.PROJECT_PATH, 'src/components'),
148
+ 'package': path.join(process.env.PROJECT_PATH, 'src/package'),
149
+ 'assets': path.join(process.env.PROJECT_PATH, 'src/assets'),
150
+ 'template': path.join(__dirname, '../template')
151
+ }
152
+ },
153
+ optimization: {
154
+ minimize: false,
155
+ minimizer: [
156
+ new TerserPlugin({
157
+ extractComments: false//不将注释提取到单独的文件中
158
+ })
159
+ ],
160
+ splitChunks: {
161
+ chunks: 'all'
162
+ }
163
+ },
164
+ devServer: {
165
+ open: true,
166
+ client: {
167
+ progress: true
168
+ }
169
+ }
170
+ };
171
+
172
+ const configOverrides = path.resolve(process.env.PROJECT_PATH, 'config-overrides.js');
173
+ if (fs.existsSync(configOverrides)) {
174
+ try {
175
+ const overrides = require(path.resolve(process.env.PROJECT_PATH, 'config-overrides.js'));
176
+ conf = overrides(conf);
177
+ console.log('snack config overrides');
178
+ } catch (err) {
179
+ console.error('SnackCLI Error:', err);
180
+ }
181
+ }
182
+
183
+ module.exports = conf;
@@ -0,0 +1,180 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const minimist = require('minimist');
4
+ const TerserPlugin = require('terser-webpack-plugin');
5
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
6
+ const CopyWebpackPlugin = require('copy-webpack-plugin');
7
+ // 获取命令行参数
8
+ let argv = minimist(process.argv.slice(2), {
9
+ default: {
10
+ mode: 'development'
11
+ }
12
+ });
13
+ // build mode
14
+ const isDevelopment = argv.mode === 'development';
15
+ const isProduction = argv.mode ? argv.mode === 'production' : true;
16
+ // paths
17
+ const projectpath = process.env.PROJECT_PATH;
18
+ const outPath = process.env.PROJECT_OUT_PATH;
19
+ const snackConfig = JSON.parse(process.env.PROJECT_SNACK_CONFIG);
20
+ const entryConfig = snackConfig.entry;
21
+ const templatePath = path.resolve(process.env.PROJECT_TEMPLATE_PATH, 'entry');
22
+ const templatePkgPath = entryConfig && entryConfig.template && entryConfig.template.entry ? path.resolve(process.env.PROJECT_PATH, entryConfig.template.entry) : ''
23
+ const hash = String(Math.random() * 1000000 | 0) + String(Math.random() * 1000000 | 0);
24
+ const pluginJs = entryConfig.js;
25
+ const pluginCss = entryConfig.css;
26
+ let jsFile = fs.readFileSync(path.join(templatePath, 'index.tsx'), {encoding: 'utf8'});
27
+ // 外部自定义样式
28
+ if (pluginJs) {
29
+ const p = `../../../${pluginJs.replace(/^(\/|\.\/)/, '')}`;
30
+ jsFile = jsFile.replace('/** import plugin js **/', `import '${p}'`);
31
+ console.log('外挂JS: ', path.resolve(templatePath, p));
32
+ }
33
+ if (pluginCss) {
34
+ const p = `../../../${pluginCss.replace(/^(\/|\.\/)/, '')}`;
35
+ jsFile = jsFile.replace('/** import plugin css **/', `import '${p}'`);
36
+ console.log('外挂CSS: ', path.resolve(templatePath, p));
37
+ }
38
+ fs.outputFileSync(path.join(templatePath, 'index.tsx'), jsFile);
39
+
40
+ // 复制资源
41
+ const copy = [];
42
+ copy.push({
43
+ from: entryConfig.favicon ? path.resolve(projectpath, entryConfig.favicon) : path.resolve(process.env.PROJECT_TEMPLATE_PATH, 'favicon.svg'),
44
+ to: path.resolve(outPath)
45
+ });
46
+ copy.push({
47
+ from: path.resolve(process.env.PROJECT_TEMPLATE_PATH, 'minified.min.js'),
48
+ to: path.resolve(outPath)
49
+ });
50
+ copy.push({
51
+ from: path.resolve(process.env.PROJECT_TEMPLATE_PATH, 'proxy.min.js'),
52
+ to: path.resolve(outPath)
53
+ });
54
+ // 所要复制到入口文件的文件
55
+ if (entryConfig.files instanceof Array) {
56
+ entryConfig.files.forEach(file => {
57
+ const filePath = path.resolve(projectpath, file);
58
+ const stat = fs.statSync(filePath);
59
+ let targetPath = path.resolve(outPath);
60
+ if (stat.isDirectory()) {
61
+ const pathParse = path.parse(filePath);
62
+ targetPath = path.resolve(outPath, pathParse.name);
63
+ }
64
+ copy.push({
65
+ from: filePath,
66
+ to: targetPath
67
+ });
68
+ });
69
+ }
70
+ // 清理目录
71
+ fs.removeSync(outPath);
72
+
73
+ module.exports = {
74
+ cache: {
75
+ type: 'filesystem',
76
+ allowCollectingMemory: true
77
+ },
78
+ performance: {
79
+ hints: false // 关闭性能提示
80
+ },
81
+ mode: isDevelopment ? 'development' : 'production',
82
+ target: ['web', 'es5'],
83
+ entry: path.join(templatePath, 'index.tsx'),
84
+ devtool: false,
85
+ output: {
86
+ filename: `[name].js`,
87
+ path: outPath,
88
+ publicPath: '/'
89
+ },
90
+ plugins: [
91
+ new CopyWebpackPlugin({patterns: copy}, {noErrorOnMissing: true}),
92
+ // new CopyWebpackPlugin({patterns: coyps}, {noErrorOnMissing: true}),
93
+ new HtmlWebpackPlugin(
94
+ {
95
+ title: entryConfig.title || 'Snack Entry',
96
+ filename: path.join(outPath, 'index.html'),
97
+ template: templatePkgPath || path.join(templatePath, 'index.html'),
98
+ hash: true,
99
+ inject: false,
100
+ jshash: hash, // js hash 参数
101
+ jsvers: {
102
+ id: entryConfig.id,
103
+ type: entryConfig.type || '_',
104
+ mobile: {
105
+ id: entryConfig.mobile && entryConfig.mobile.id || null,
106
+ type: entryConfig.mobile && entryConfig.mobile.type || '_'
107
+ },
108
+ service: entryConfig.service,
109
+ devServer: entryConfig.devServer,
110
+ favicon: entryConfig.favicon === undefined ? './favicon.svg' : '',
111
+ loaderjs: `main.js?_=${hash}`
112
+ }
113
+ }
114
+ )
115
+ ],
116
+ // loader配置
117
+ module: {
118
+ rules: [
119
+ {
120
+ test: /\.(ts|tsx|js|jsc|cjs)?$/,
121
+ loader: 'swc-loader',
122
+ options: {
123
+ sync: true,
124
+ jsc: {
125
+ parser: {
126
+ 'syntax': 'typescript',
127
+ 'tsx': true
128
+ },
129
+ 'target': 'es5',
130
+ 'keepClassNames': true,
131
+ 'loose': true
132
+ }
133
+ }
134
+ },
135
+ // 样式loader
136
+ {
137
+ // 匹配哪些文件
138
+ test: /\.(css|sass|scss)$/,
139
+ // 使用哪些loader进行处理
140
+ use: [
141
+ // use数组中loader执行顺序:从右到左,从下到上,依次执行(先执行css-loader)
142
+ // style-loader:创建style标签,将js中的样式资源插入进去,添加到head中生效
143
+ 'style-loader',
144
+ // css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串
145
+ 'css-loader',
146
+ // less-loader:将less文件编译成css文件,需要下载less-loader和less
147
+ 'sass-loader'
148
+ ]
149
+ }
150
+ ]
151
+ },
152
+ resolve: {
153
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
154
+ alias: {
155
+ 'src': path.join(process.env.PROJECT_PATH, 'src'),
156
+ 'components': path.join(process.env.PROJECT_PATH, 'src/components'),
157
+ 'package': path.join(process.env.PROJECT_PATH, 'src/package'),
158
+ 'assets': path.join(process.env.PROJECT_PATH, 'src/assets')
159
+ }
160
+ },
161
+ optimization: {
162
+ minimize: isProduction,
163
+ minimizer: [
164
+ new TerserPlugin(
165
+ {
166
+ parallel: true,//使用多进程并发运行以提高构建速度 Boolean|Number 默认值: true
167
+ terserOptions: {
168
+ compress: {
169
+ drop_debugger: true,//移除自动断点功能;
170
+ },
171
+ format: {
172
+ comments: false,//删除注释
173
+ },
174
+ },
175
+ extractComments: false,//是否将注释剥离到单独的文件中
176
+ }
177
+ )
178
+ ]
179
+ }
180
+ };