UNPKG

7.5 kBPlain TextView Raw
1import * as FriendlyErrorsWebpackPlugin from "friendly-errors-webpack-plugin";
2import * as CopyWebpackPlugin from "copy-webpack-plugin";
3import * as OptimizeCssAssetsPlugin from "optimize-css-assets-webpack-plugin";
4import * as SpeedMeasurePlugin from "speed-measure-webpack-plugin";
5import * as CleanWebpackPlugin from "clean-webpack-plugin";
6import * as HtmlWebpackPlugin from "html-webpack-plugin";
7import * as MiniCssExtractPlugin from "mini-css-extract-plugin";
8import { join, resolve } from "path";
9import * as webpack from "webpack";
10import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
11import * as webpackMerge from "webpack-merge";
12import * as nodeExternals from "webpack-node-externals";
13import * as WebpackBar from "webpackbar";
14import * as TerserPlugin from "terser-webpack-plugin";
15import {
16 getFile,
17 getPaths,
18 isBackEndConfig,
19 makeDevEntries,
20 resolveContext,
21 resolveHtmlTemplate,
22 resolveLocal,
23 rootPath
24} from "./utils";
25
26export interface IUserConfig {
27 rules;
28 plugins;
29 mode: string;
30}
31
32interface IConfig {
33 devServer: any;
34}
35
36const configuration = (
37 env = "development",
38 userConfig,
39 isDebugging = false,
40 port?
41): Partial<webpack.Configuration & IConfig> => {
42 const isDev = env !== "production";
43 const context = rootPath;
44 const paths = getPaths(userConfig.paths);
45
46 const allConfigs: Partial<IUserConfig> = {
47 rules: {
48 typescript: {
49 test: /\.tsx?$/,
50 use: [
51 {
52 loader: require.resolve("ts-loader"),
53 options: {
54 context: rootPath,
55 transpileOnly: true,
56 experimentalWatchApi: true
57 }
58 }
59 ],
60 include: paths.src,
61 exclude: /node_modules/
62 },
63 babel: {
64 test: /\.jsx?$/,
65 use: [
66 {
67 loader: require.resolve("babel-loader")
68 }
69 ],
70 include: paths.src,
71 exclude: /node_modules/
72 },
73 html: {
74 test: /\.(html)$/,
75 use: { loader: require.resolve("html-loader") },
76 include: paths.src,
77 exclude: /node_modules/
78 },
79 scss: {
80 test: /\.(sa|sc|c)ss$/,
81 use: [
82 isDev ? require.resolve("style-loader") : MiniCssExtractPlugin.loader,
83 {
84 loader: require.resolve("css-loader"),
85 options: { sourceMap: !isDev, importLoaders: 1 }
86 },
87 {
88 loader: require.resolve("postcss-loader"),
89 options: { sourceMap: !isDev, plugins: [require("autoprefixer")] }
90 },
91 {
92 loader: require.resolve("sass-loader"),
93 options: { sourceMap: !isDev }
94 }
95 ]
96 },
97 images: {
98 test: /\.(png|svg|jpg|gif)$/,
99 loader: require.resolve("url-loader"),
100 options: { limit: 10000, name: "images/[name].[hash:7].[ext]" }
101 },
102 fonts: {
103 test: /\.(woff|woff2|eot|ttf|otf)$/,
104 loader: require.resolve("url-loader"),
105 options: { limit: 10000, name: "fonts/[name].[hash:7].[ext]" }
106 },
107 media: {
108 test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
109 loader: require.resolve("url-loader"),
110 options: { limit: 10000, name: "media/[name].[hash:7].[ext]" }
111 }
112 },
113 plugins: {
114 miniCssExtract: new MiniCssExtractPlugin({
115 filename: isDev ? "[name].css" : "css/[name].[contenthash].css",
116 chunkFilename: isDev ? "[id].css" : "css/[id].[chunkhash].css"
117 }),
118 friendlyErrors: new FriendlyErrorsWebpackPlugin(),
119 define: new webpack.DefinePlugin({
120 "process.env": isDev
121 ? getFile("./env.development.ts")
122 : getFile("./env.production.ts")
123 }),
124 html: new HtmlWebpackPlugin({
125 filename: "index.html",
126 template: resolveHtmlTemplate(),
127 inject: true,
128 minify: isDev
129 ? false
130 : {
131 removeComments: true,
132 collapseWhitespace: true,
133 removeAttributeQuotes: true
134 }
135 }),
136 clean: new CleanWebpackPlugin(["dist"], { root: rootPath }),
137 hmr: new webpack.HotModuleReplacementPlugin(),
138 webpackbar: new WebpackBar({
139 name: "TypePack"
140 }),
141 analyze: new BundleAnalyzerPlugin(),
142 copyStatic: new CopyWebpackPlugin([
143 {
144 from: join(rootPath, "static"),
145 to: paths.outputFolder,
146 ignore: [".*"]
147 }
148 ])
149 }
150 };
151 const { rules, plugins }: IUserConfig = {
152 ...allConfigs,
153 ...userConfig
154 };
155
156 const commonConfig = {
157 context,
158 mode: isDev ? "development" : "production",
159 devtool: isDev ? "cheap-module-eval-source-map" : "source-map",
160 entry:
161 isDev && !isBackEndConfig(userConfig.mode)
162 ? makeDevEntries(paths.entry, port)
163 : paths.entry,
164 optimization: isDev
165 ? {}
166 : {
167 removeAvailableModules: false,
168 removeEmptyChunks: false,
169 minimizer: [
170 new TerserPlugin({
171 cache: true,
172 parallel: true,
173 sourceMap: true
174 }),
175 new OptimizeCssAssetsPlugin({
176 cssProcessor: require("cssnano"),
177 cssProcessorPluginOptions: {
178 preset: [
179 "default",
180 {
181 discardComments: {
182 removeAll: true
183 }
184 }
185 ]
186 },
187 canPrint: true
188 })
189 ],
190 splitChunks: {
191 chunks: "all"
192 }
193 },
194 resolve: {
195 symlinks: false,
196 extensions: [".tsx", ".ts", ".js", ".jsx", ".json"],
197 modules: [
198 "node_modules",
199 resolveContext(context, "node_modules"),
200 resolveLocal("node_modules")
201 ],
202 alias: {
203 "@": paths.src
204 }
205 },
206 resolveLoader: {
207 modules: [
208 "node_modules",
209 resolveContext(context, "node_modules"),
210 resolveLocal("node_modules")
211 ]
212 },
213 module: {
214 rules: [rules.typescript, rules.babel]
215 },
216 plugins: [
217 plugins.friendlyErrors,
218 plugins.webpackbar,
219 plugins.clean,
220 plugins.define,
221 ...(process.env.BUNDLE_ANALYZE ? [plugins.analyze] : [])
222 ],
223 output: {
224 publicPath: "/",
225 filename: isDev ? "js/[name].js" : "js/[name].[chunkhash].js",
226 chunkFilename: isDev ? "js/[id].js" : "js/[id].[chunkhash].js",
227 path: paths.outputFolder,
228 libraryTarget: "umd",
229 pathinfo: false
230 }
231 };
232
233 const webAppConfig = webpackMerge(commonConfig, {
234 module: {
235 rules: [rules.html, rules.scss, rules.images, rules.fonts, rules.media]
236 },
237 plugins: [
238 plugins.html,
239 ...(isDev ? [plugins.hmr] : [plugins.miniCssExtract])
240 ]
241 });
242
243 const backEndConfig = webpackMerge(commonConfig, {
244 target: "node",
245 externals: [nodeExternals()],
246 output: {
247 filename: "index.js",
248 path: resolve("./dist"),
249 libraryTarget: "commonjs2"
250 }
251 });
252
253 let resultConfig: webpack.Configuration = webAppConfig;
254
255 if (isBackEndConfig(userConfig.mode)) {
256 resultConfig = backEndConfig;
257 }
258
259 if (typeof userConfig.config === "function") {
260 userConfig.config(resultConfig);
261 }
262
263 if (isDebugging) {
264 console.log(JSON.stringify(resultConfig));
265 }
266
267 const smp = new SpeedMeasurePlugin({
268 disable: !process.env.SMP
269 });
270 return smp.wrap(resultConfig);
271};
272
273export default configuration;