@@ -195,4 +195,204 @@ module.exports = {
195195 } ,
196196 ] ,
197197 } ,
198- } ;
198+ } ;
199+
200+
201+
202+ // SET UP PRODUCTION BUILD
203+
204+ // the goal is to end up with a build folder composed of index.html, bundle.js and styles.css
205+
206+ // package.json
207+ {
208+ "name" : "ps-redux" ,
209+ "description" : "React and Redux Pluralsight course by Cory House" ,
210+ "scripts" : {
211+ "start" : "run-p start:dev start:api" ,
212+ "start:dev" : "webpack serve --config webpack.config.dev.js --port 3000" ,
213+ "prestart:api" : "node tools/createMockDb.js" ,
214+ "start:api" : "node tools/apiServer.js" ,
215+ "test" : "jest --watchAll" ,
216+ "test:ci" : "jest" ,
217+ "clean:build" : "rimraf ./build && mkdir build" ,
218+ "prebuild" : "run-p clean:build test:ci" ,
219+ "build" : "webpack --config webpack.config.prod.js" ,
220+ "postbuild" : "run-p start:api serve:build" ,
221+ "serve:build" : "http-server ./build"
222+ } ,
223+ "jest" : {
224+ "setupFiles" : [
225+ "./tools/testSetup.js"
226+ ] ,
227+ "testEnvironment" : "jsdom" ,
228+ "moduleNameMapper" : {
229+ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$" : "<rootDir>/tools/fileMock.js" ,
230+ "\\.(css|less)$" : "<rootDir>/tools/styleMock.js"
231+ }
232+ } ,
233+ "dependencies" : {
234+ "bootstrap" : "5.0.2" ,
235+ "immer" : "9.0.5" ,
236+ "prop-types" : "15.7.2" ,
237+ "react" : "17.0.2" ,
238+ "react-dom" : "17.0.2" ,
239+ "react-redux" : "7.2.4" ,
240+ "react-router-dom" : "5.2.0" ,
241+ "react-toastify" : "7.0.4" ,
242+ "redux" : "4.1.0" ,
243+ "redux-thunk" : "2.3.0" ,
244+ "reselect" : "4.0.0"
245+ } ,
246+ "devDependencies" : {
247+ "@babel/core" : "7.14.6" ,
248+ "@testing-library/react" : "^12.0.0" ,
249+ "@wojtekmaj/enzyme-adapter-react-17" : "^0.6.2" ,
250+ "babel-eslint" : "10.1.0" ,
251+ "babel-loader" : "8.2.2" ,
252+ "babel-preset-react-app" : "10.0.0" ,
253+ "css-loader" : "5.2.6" ,
254+ "cssnano" : "5.0.6" ,
255+ "enzyme" : "3.11.0" ,
256+ "eslint" : "7.30.0" ,
257+ "eslint-loader" : "4.0.2" ,
258+ "eslint-plugin-import" : "2.23.4" ,
259+ "eslint-plugin-react" : "7.24.0" ,
260+ "fetch-mock" : "9.11.0" ,
261+ "html-webpack-plugin" : "5.3.2" ,
262+ "http-server" : "0.12.3" ,
263+ "jest" : "27.0.6" ,
264+ "json-server" : "0.16.3" ,
265+ "mini-css-extract-plugin" : "2.1.0" ,
266+ "node-fetch" : "^2.6.1" ,
267+ "npm-run-all" : "4.1.5" ,
268+ "postcss" : "^8.3.5" ,
269+ "postcss-loader" : "6.1.1" ,
270+ "react-test-renderer" : "17.0.2" ,
271+ "redux-immutable-state-invariant" : "2.1.0" ,
272+ "redux-mock-store" : "1.5.4" ,
273+ "rimraf" : "3.0.2" ,
274+ "style-loader" : "3.0.0" ,
275+ "webpack" : "5.44.0" ,
276+ "webpack-bundle-analyzer" : "4.4.2" ,
277+ "webpack-cli" : "4.9.0" ,
278+ "webpack-dev-server" : "3.11.2"
279+ } ,
280+ "engines" : {
281+ "node" : ">=8"
282+ } ,
283+ "babel" : {
284+ "presets" : [
285+ "babel-preset-react-app"
286+ ]
287+ } ,
288+ "eslintConfig" : {
289+ "extends" : [
290+ "eslint:recommended" ,
291+ "plugin:react/recommended" ,
292+ "plugin:import/errors" ,
293+ "plugin:import/warnings"
294+ ] ,
295+ "parser" : "babel-eslint" ,
296+ "parserOptions" : {
297+ "ecmaVersion" : 2018 ,
298+ "sourceType" : "module" ,
299+ "ecmaFeatures" : {
300+ "jsx" : true
301+ }
302+ } ,
303+ "env" : {
304+ "browser" : true ,
305+ "node" : true ,
306+ "es6" : true ,
307+ "jest" : true
308+ } ,
309+ "rules" : {
310+ "no-debugger" : "off" ,
311+ "no-console" : "off" ,
312+ "no-unused-vars" : "warn" ,
313+ "react/prop-types" : "warn"
314+ } ,
315+ "settings" : {
316+ "react" : {
317+ "version" : "detect"
318+ }
319+ } ,
320+ "root" : true
321+ }
322+ }
323+
324+ // webpack.config.prod.js
325+ const webpack = require ( 'webpack' ) ;
326+ const path = require ( 'path' ) ;
327+ const HtmlWebpackPlugin = require ( 'html-webpack-plugin' ) ;
328+ const MiniCssExtractPlugin = require ( 'mini-css-extract-plugin' ) ;
329+ const webpackBundleAnalyzer = require ( 'webpack-bundle-analyzer' ) ;
330+ process . env . NODE_ENV = 'production' ;
331+ module . exports = {
332+ mode : 'production' ,
333+ target : 'web' ,
334+ devtool : 'source-map' ,
335+ entry : './src/index' ,
336+ output : {
337+ path : path . resolve ( __dirname , 'build' ) ,
338+ publicPath : '/' ,
339+ filename : 'bundle.js' ,
340+ } ,
341+ plugins : [
342+ new webpackBundleAnalyzer . BundleAnalyzerPlugin ( { analyzerMode : 'static' } ) ,
343+ new MiniCssExtractPlugin ( {
344+ filename : '[name].[contenthash].css' ,
345+ } ) ,
346+ new webpack . DefinePlugin ( {
347+ 'process.env.NODE_ENV' : JSON . stringify ( process . env . NODE_ENV ) ,
348+ 'process.env.API_URL' : JSON . stringify ( 'http://localhost:3001' ) ,
349+ } ) ,
350+ new HtmlWebpackPlugin ( {
351+ template : 'src/index.html' ,
352+ favicon : 'src/favicon.ico' ,
353+ minify : {
354+ // see https://github.com/kangax/html-minifier#options-quick-reference
355+ removeComments : true ,
356+ collapseWhitespace : true ,
357+ removeRedundantAttributes : true ,
358+ useShortDoctype : true ,
359+ removeEmptyAttributes : true ,
360+ removeStyleLinkTypeAttributes : true ,
361+ keepClosingSlash : true ,
362+ minifyJS : true ,
363+ minifyCSS : true ,
364+ minifyURLs : true ,
365+ } ,
366+ } ) ,
367+ ] ,
368+ module : {
369+ rules : [
370+ {
371+ test : / \. ( j s | j s x ) $ / ,
372+ exclude : / n o d e _ m o d u l e s / ,
373+ use : [ 'babel-loader' , 'eslint-loader' ] ,
374+ } ,
375+ {
376+ test : / ( \. c s s ) $ / ,
377+ use : [
378+ MiniCssExtractPlugin . loader ,
379+ {
380+ loader : 'css-loader' ,
381+ options : {
382+ sourceMap : true ,
383+ } ,
384+ } ,
385+ {
386+ loader : 'postcss-loader' ,
387+ options : {
388+ postcssOptions : {
389+ plugins : [ ( ) => [ require ( 'cssnano' ) ] ] ,
390+ } ,
391+ sourceMap : true ,
392+ } ,
393+ } ,
394+ ] ,
395+ } ,
396+ ] ,
397+ } ,
398+ } ;
0 commit comments