1. // config/paths.js
    2. const fs = require('fs')
    3. const path = require('path')
    4. // process.cwd() 返回 Node.js 进程的当前工作目录
    5. // 注:__dirname 标识被执行 js 文件所在的目录
    6. // fs.realpathSync() 通过解析 .、.. 和符号链接,同步地计算规范路径名
    7. // path.resolve() 将路径或路径片段的序列解析为绝对路径。
    8. const appDirectory = fs.realpathSync(process.cwd());
    9. const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
    10. module.exports = {
    11. resolveApp,
    12. appPublic: resolveApp('public'),
    13. appHtml: resolveApp('public/index.html'),
    14. appSrc: resolveApp('src'),
    15. appDist: resolveApp('dist'),
    16. appTsConfig: resolveApp('tsconfig.json'),
    17. }
    1. // config/webpack.common.js
    2. const HtmlWebpackPlugin = require('html-webpack-plugin');
    3. const { appSrc, appHtml } = require('./paths');
    4. module.exports = {
    5. entry: {
    6. index: './src/index.tsx',
    7. },
    8. resolve: {
    9. extensions: ['.tsx', '.ts', '.js'],
    10. },
    11. module: {
    12. rules: [
    13. {
    14. test: /\.(js|ts|jsx|tsx)$/,
    15. include: appSrc,
    16. use: [{
    17. loader: 'babel-loader',
    18. options: {
    19. presets: ['@babel/preset-env', ["@babel/preset-react", { "runtime": "automatic" }]],
    20. }
    21. }],
    22. },
    23. {
    24. test: /\.(png|svg|jpg|jpeg|gif)$/i,
    25. include: [appSrc],
    26. type: 'asset/resource',
    27. generator: {
    28. filename: 'images/[hash][ext]'
    29. },
    30. },
    31. {
    32. test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
    33. include: [appSrc],
    34. type: 'asset/resource',
    35. generator: {
    36. filename: 'fonts/[hash][ext]'
    37. },
    38. },
    39. {
    40. test: /\.module\.(less)$/,
    41. include: appSrc,
    42. use: [
    43. 'style-loader',
    44. {
    45. loader: 'css-loader',
    46. options: {
    47. // Enable CSS Modules features
    48. modules: true,
    49. importLoaders: 2,
    50. // 0 => no loaders (default);
    51. // 1 => postcss-loader;
    52. // 2 => postcss-loader, less-loader
    53. },
    54. },
    55. {
    56. loader: 'postcss-loader',
    57. options: {
    58. postcssOptions: {
    59. plugins: [
    60. [
    61. // postcss-preset-env includes autoprefixer
    62. 'postcss-preset-env',
    63. ],
    64. ],
    65. },
    66. },
    67. },
    68. 'less-loader',
    69. ],
    70. },
    71. ],
    72. },
    73. plugins: [
    74. new HtmlWebpackPlugin({
    75. title: 'Stand up man!',
    76. template: appHtml,
    77. })
    78. ]
    79. };
    1. // config/webpack.dev.js
    2. const { merge } = require('webpack-merge');
    3. const common = require('./webpack.common');
    4. const { appDist } = require('./paths');
    5. const devConfig = {
    6. mode: 'development',
    7. output: {
    8. filename: '[name].bundle.js',
    9. path: appDist,
    10. clean: true,
    11. },
    12. devtool: 'eval-cheap-module-source-map',
    13. devServer: {
    14. //将 dist 目录下的文件 serve 到 localhost:3000 下
    15. hot: true,
    16. port: 3000,
    17. static: appDist
    18. },
    19. }
    20. module.exports = merge(common, devConfig)
    1. // config/webpack.prod.js
    2. const { merge } = require('webpack-merge');
    3. const common = require('./webpack.common')
    4. const { appDist } = require('./paths');
    5. const prodConfig = {
    6. mode: 'production',
    7. output: {
    8. filename: '[name].[contenthash].bundle.js',
    9. path: appDist,
    10. clean: true,
    11. },
    12. }
    13. module.exports = merge(common, prodConfig)
    1. {
    2. "compilerOptions": {
    3. "target": "es5", // 目标语言的版本
    4. "lib": [
    5. "dom",
    6. "dom.iterable",
    7. "esnext"
    8. ], // TS需要引用的库,即声明文件
    9. "allowJs": true, // 允许编译器编译JSJSX文件
    10. "skipLibCheck": true, // 忽略所有的声明文件(*.d.ts)的类型检查
    11. "esModuleInterop": true, // 允许export=导出,由import from 导入
    12. "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入
    13. "strict": true,
    14. "forceConsistentCasingInFileNames": true, // 禁止对同一个文件的不一致的引用
    15. "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即无break语句后面不会执行)
    16. "module": "esnext", // 指定生成代码的模板标准
    17. "moduleResolution": "node", // 使用哪种模块解析策略
    18. "resolveJsonModule": true, // 是否可以导入 JSON 模块
    19. "isolatedModules": true, // 将每个文件作为单独的模块
    20. "noEmit": true, // 不生成输出文件
    21. "jsx": "react-jsx" // .tsx文件里支持JSX "React" "Preserve"
    22. },
    23. "include": [
    24. "src"
    25. ]
    26. }
    1. {
    2. "name": "stand-up-man",
    3. "version": "0.0.1",
    4. "description": "stand up man!",
    5. "private": true,
    6. "scripts": {
    7. "dev": "cross-env NODE_ENV=development webpack serve --open --config config/webpack.dev.js",
    8. "build": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js"
    9. },
    10. "keywords": [],
    11. "author": "hesetiema",
    12. "license": "ISC",
    13. "devDependencies": {
    14. "@babel/core": "^7.18.5",
    15. "@babel/preset-env": "^7.18.2",
    16. "@babel/preset-react": "^7.17.12",
    17. "@types/react": "^18.0.14",
    18. "@types/react-dom": "^18.0.5",
    19. "babel-loader": "^8.2.5",
    20. "cross-env": "^7.0.3",
    21. "css-loader": "^6.7.1",
    22. "html-webpack-plugin": "^5.5.0",
    23. "less": "^4.1.3",
    24. "less-loader": "^11.0.0",
    25. "postcss": "^8.4.14",
    26. "postcss-loader": "^7.0.0",
    27. "postcss-preset-env": "^7.7.1",
    28. "react": "^18.2.0",
    29. "react-dom": "^18.2.0",
    30. "style-loader": "^3.3.1",
    31. "ts-loader": "^9.3.0",
    32. "typescript": "^4.7.4",
    33. "webpack": "^5.73.0",
    34. "webpack-cli": "^4.10.0",
    35. "webpack-dev-server": "^4.9.2",
    36. "webpack-merge": "^5.8.0"
    37. }
    38. }