现在,基本上前端的项目打包都会用上 ​webpack​​,因为 ​webpack​​ 提供了无与伦比强大的功能和生态。但在创建一个项目的时候,总是免不了要配置 ​webpack​,很是麻烦。

简化 ​webpack​​ 配置的一种方式是使用社区封装好的库,比如 roadhog。 ​roadhog​​ 封装了 ​webpack​​ 的一些基础配置,然后暴露一些额外配置的接口,并附加本地数据模拟功能( ​mock​),详情可以参考 roadhog 主页。

另一种方式是自己封装 ​webpack​,这样做自己能够更好的掌控项目。

1. 要封装哪些功能

一般搭建一个项目至少需要两种功能:本地开发调试、构建产品代码。

其他的诸如测试、部署到服务器、代码检查、格式优化等功能则不在这篇文章讲解范围,如果有意了解,可以查看我的其他文章。

2. 基础配置

2.1 目录结构(示例,配合后面的代码讲解)
  1. ​package.json​
  2. ​dev.js                       # 本地开发脚本​
  3. ​build.js                     # 产品构建脚本​
  4. ​analyze.js                   # 模块大小分析(可选)​

  5. ​# 单页面结构​
  6. ​src/                         # 源代码目录​
  7. ​  - index.js                 # js 入口文件​
  8. ​  - index.html               # html 入口文件​
  9. ​  - ...                      # 其他文件​

  10. ​# 多页面结构​
  11. ​src/                         # 源代码目录​
  12. ​  - home/                    # home 页面工作空间​
  13. ​    - index.js               # home 页面 js 入口文件​
  14. ​    - index.html             # home 页面 html 入口文件​
  15. ​    - ...                    # home 页面其他文件​

  16. ​  - explore/                 # explore 页面工作空间​
  17. ​    - index.js               # explore 页面 js 入口文件​
  18. ​    - index.html             # explore 页面 html 入口文件​
  19. ​    - ...                    # explore 页面其他文件 ​

  20. ​  - about/                   # about 目录​
  21. ​    - company                # about/company 页面工作空间​
  22. ​      - index.js             # about/company 页面 js 入口文件​
  23. ​      - index.html           # about/company 页面 html 入口文件​
  24. ​      - ...                  # about/company 页面其他文件​

  25. ​    - platform               # about/platform 页面工作空间​
  26. ​      - index.js             # about/platform 页面 js 入口文件​
  27. ​      - index.html           # about/platform 页面 html 入口文件​
  28. ​      - ...                  # about/platform 页面其他文件    ​

  29. ​  - ...                      # 更多页面        ​
2.2 基础 npm 包
  1. ​# package.json​

  2. ​"devDependencies": {​
  3. ​  "@babel/core": "^7.1.2",                  # babel core       ​
  4. ​  "@babel/plugin-syntax-dynamic-import": "^7.0.0",         # import() 函数支持​
  5. ​  "@babel/plugin-transform-react-jsx": "^7.0.0",           # react jsx 支持​
  6. ​  "@babel/preset-env": "^7.1.0",            # es6+ 转 es5​
  7. ​  "@babel/preset-flow": "^7.0.0",           # flow 支持​
  8. ​  "@babel/preset-react": "^7.0.0",          # react 支持​
  9. ​  "autoprefixer": "^9.1.5",                 # css 自动添加厂家前缀 -webkit-, -moz-​
  10. ​  "babel-loader": "^8.0.4",                 # webpack 加载 js 的 loader​
  11. ​  "babel-plugin-component": "^1.1.1",       # 如果使用 element ui,需要用到这个​
  12. ​  "babel-plugin-flow-runtime": "^0.17.0",   # flow-runtime 支持 ​
  13. ​  "babel-plugin-import": "^1.9.1",          # 如果使用 ant-design,需要用到这个​
  14. ​  "browser-sync": "^2.24.7",                # 浏览器实例组件,用于本地开发调试​
  15. ​  "css-loader": "^1.0.0",                   # webpack 加载 css 的 loader​
  16. ​  "chalk": "^2.4.1",                        # 让命令行的信息有颜色​
  17. ​  "file-loader": "^2.0.0",                  # webpack 加载静态文件的 loader​
  18. ​  "flow-runtime": "^0.17.0",                # flow-runtime 包​
  19. ​  "html-loader": "^0.5.5",                  # webpack 加载 html 的 loader​
  20. ​  "html-webpack-include-assets-plugin": "^1.0.5",          # 给 html 文件添加额外静态文件链接的插件​
  21. ​  "html-webpack-plugin": "^3.2.0",          # 更方便操作 html 文件的插件​
  22. ​  "less": "^3.8.1",                         # less 转 css​
  23. ​  "less-loader": "^4.1.0",                  # webpack 加载 less 的 loader​
  24. ​  "mini-css-extract-plugin": "^0.4.3",      # 提取 css 单独打包​
  25. ​  "minimist": "^1.2.0",                     # process.argv 更便捷处理​
  26. ​  "node-sass": "^4.9.3",                    # scss 转 css​
  27. ​  "optimize-css-assets-webpack-plugin": "^5.0.1",          # 优化 css 打包,包括压缩​
  28. ​  "postcss-loader": "^3.0.0",               # 对 css 进行更多操作,比如添加厂家前缀​
  29. ​  "sass-loader": "^7.1.0",                  # webpack 加载 scss 的 loader​
  30. ​  "style-loader": "^0.23.0",                # webpack 加载 style 的 loader​
  31. ​  "uglifyjs-webpack-plugin": "^2.0.1",      # 压缩 js 的插件​
  32. ​  "url-loader": "^1.1.1",                   # file-loader 的升级版​
  33. ​  "vue-loader": "^15.4.2",                  # webpack 加载 vue 的 loader​
  34. ​  "vue-template-compiler": "^2.5.17",       # 配合 vue-loader 使用的 ​
  35. ​  "webpack": "^4.20.2",                     # webpack 模块​
  36. ​  "webpack-bundle-analyzer": "^3.0.2",      # 分析当前打包各个模块的大小,决定哪些需要单独打包​
  37. ​  "webpack-dev-middleware": "^3.4.0",       # webpack-dev-server 中间件​
  38. ​  "webpack-hot-middleware": "^2.24.2"       # 热更新中间件​
  39. ​}​
2.3 基本命令
  1. ​# package.json​

  2. ​"scripts": {​
  3. ​  "dev": "node dev.js",​
  4. ​  "build": "node build.js",​
  5. ​  "analyze": "node analyze.js",​
  6. ​}​
  7. ​npm run dev                                 # 开发​
  8. ​npm run build                               # 构建​
  9. ​npm run analyze                             # 模块分析​

如果需要支持多入口构建,在命令后面添加参数:

  1. ​npm run dev -- home                         # 开发 home 页面 ​
  2. ​npm run analyze -- explore                  # 模块分析 explore 页面 ​

  3. ​# 构建多个页面 ​
  4. ​npm run build -- home explore about/* about/all --env test/prod  ​

说明:

  • ​home​​​、 ​​explore​​​ 确定构建的页面; ​​about/*​​​、 ​​about/all​​​ 指 ​​about​​​ 目录下所有的页面; ​​all​​​、 ​​*​​ 整个项目所有的页面。
  • 有时候可能还会针对不同的服务器环境(比如测试机、正式机)做出不同的构建,可以在后面加参数。
  • ​--​​​ 用来分割 ​​npm​​ 本身的参数与脚本参数,参考 npm - run-script 了解详情。
2.4 dev.js 配置

开发一般用需要用到下面的组件:

  • webpack
  • webpack-dev-server 或 webpack-dev-middleware
  • webpack-hot-middleware
  • HotModuleReplacementPlugin
  • browser-sync
  1. ​const minimist = require('minimist');​
  2. ​const webpack = require('webpack');​
  3. ​const HtmlWebpackPlugin = require('html-webpack-plugin');​
  4. ​const devMiddleWare = require('webpack-dev-middleware');​
  5. ​const hotMiddleWare = require('webpack-hot-middleware');​
  6. ​const browserSync = require('browser-sync');​
  7. ​const VueLoaderPlugin = require('vue-loader/lib/plugin');​

  8. ​const { HotModuleReplacementPlugin } = webpack;​

  9. ​const argv = minimist(process.argv.slice(2));​

  10. ​const page = argv._[0];​

  11. ​ // 单页面​
  12. ​const entryFile = `${__dirname}/src/index.js`;​
  13. ​// 多页面 ​
  14. ​const entryFile = `${__dirname}/src/${page}/index.js`; ​

  15. ​// 编译器对象​
  16. ​const compiler = webpack({​
  17. ​  entry: [​
  18. ​    'webpack-hot-middleware/client?reload=true',      // 热重载需要​
  19. ​    entryFile,​
  20. ​  ],​
  21. ​  output: {​
  22. ​    path: `${__dirname}/dev/`,                        // 打包到 dev 目录​
  23. ​    filename: 'index.js',​
  24. ​    publicPath: '/dev/',​
  25. ​  },​
  26. ​  plugins: [​
  27. ​    new HotModuleReplacementPlugin(),                 // 热重载插件​
  28. ​    new HtmlWebpackPlugin({                           // 处理 html​
  29. ​      // 单页面​
  30. ​      template: `${__dirname}/src/index.html`,​
  31. ​      // 多页面​
  32. ​      template: `${__dirname}/src/${page}/index.html`,​
  33. ​    }),​
  34. ​    new VueLoaderPlugin(),                            // vue-loader 所需​
  35. ​  ],​
  36. ​  module: {​
  37. ​    rules: [​
  38. ​      {                                               // js 文件加载器​
  39. ​        loader: 'babel-loader',​
  40. ​        exclude: /node_modules/,​
  41. ​        options: {​
  42. ​          presets: ['@babel/preset-env', '@babel/preset-react'],​
  43. ​          plugins: [​
  44. ​            '@babel/plugin-transform-react-jsx',​
  45. ​            '@babel/plugin-syntax-dynamic-import',​
  46. ​          ],​
  47. ​        },​
  48. ​        test: /.(js|jsx)$/,​
  49. ​      },​
  50. ​      {                                               // css 文件加载器​
  51. ​        loader: 'style-loader!css-loader',​
  52. ​        test: /.css$/,​
  53. ​      },​
  54. ​      {                                               // less 文件加载器​
  55. ​        loader: 'style-loader!css-loader!less-loader',​
  56. ​        test: /.less$/,​
  57. ​      },​
  58. ​      {                                               // scss 文件加载器​
  59. ​        loader: 'style-loader!css-loader!sass-loader',​
  60. ​        test: /.(scss|sass)$/,​
  61. ​      },​
  62. ​      {                                               // 静态文件加载器​
  63. ​        loader: 'url-loader',​
  64. ​        test: /.(gif|jpg|png|woff|woff2|svg|eot|ttf|ico)$/,​
  65. ​        options: {​
  66. ​          limit: 1,​
  67. ​        },​
  68. ​      },​
  69. ​      {                                               // html 文件加载器​
  70. ​        loader: 'html-loader',​
  71. ​        test: /.html$/,​
  72. ​        options: {​
  73. ​          attrs: ['img:src', 'link:href'],​
  74. ​          interpolate: 'require',​
  75. ​        },​
  76. ​      },​
  77. ​      {                                               // vue 文件加载器​
  78. ​        loader: 'vue-loader',​
  79. ​        test: /.vue$/,​
  80. ​      },​
  81. ​    ],​
  82. ​  },​
  83. ​  resolve: {​
  84. ​    alias: {},                                        // js 配置别名   ​
  85. ​    modules: [`${__dirname}/src`, 'node_modules'],    // 模块寻址基路径​
  86. ​    extensions: ['.js', '.jsx', '.vue', '.json'],     // 模块寻址扩展名​
  87. ​  },​
  88. ​  devtool: 'eval-source-map',                         // sourcemap ​
  89. ​  mode: 'development',                                // 指定 webpack 为开发模式​
  90. ​});​

  91. ​// browser-sync 配置​
  92. ​const browserSyncConfig = {​
  93. ​  server: {​
  94. ​    baseDir: `${__dirname}/`,                         // 静态服务器基路径,可以访问项目所有文件 ​
  95. ​  },​
  96. ​  startPath: '/dev/index.html',                       // 开启服务器窗口时的默认地址​
  97. ​};​

  98. ​// 添加中间件​
  99. ​browserSyncConfig.middleware = [​
  100. ​  devMiddleWare(compiler, {​
  101. ​    stats: 'errors-only',​
  102. ​    publicPath: '/dev/',​
  103. ​  }),​
  104. ​  hotMiddleWare(compiler),​
  105. ​];​

  106. ​browserSync.init(browserSyncConfig);                  // 初始化浏览器实例,开始调试开发​
2.5 build.js 配置

构建过程中,一般会有这些过程:

  1. 提取样式文件,单独打包、压缩、添加浏览器厂家前缀
  2. 对 ​​js​​​ 在产品模式下进行打包,并生成 ​​sourcemap​​ 文件
  3. ​html-webpack-plugin​​​ 自动把打包好的样式文件与脚本文件引用到 ​​html​​ 文件中,并压缩
  4. 对所有资源进行 hash 化处理(可选)
  5. ​const minimist = require('minimist');​
  6. ​const webpack = require('webpack');​
  7. ​const chalk = require('chalk');​
  8. ​const autoprefixer = require('autoprefixer');​
  9. ​const HtmlWebpackPlugin = require('html-webpack-plugin');​
  10. ​const MiniCssExtractPlugin = require('mini-css-extract-plugin');​
  11. ​const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');​
  12. ​const VueLoaderPlugin = require('vue-loader/lib/plugin');​

  13. ​const {yellow, red} = chalk;​

  14. ​const argv = minimist(process.argv.slice(2));​

  15. ​const pages = argv._; // ['home', 'explore', 'about/*', 'about/all']​
  16. ​const allPages = getAllPages(pages); // 根据 page 中的 `*, all` 等关键字,获取所有真正的 pages​

  17. ​// 单页面,只有一个入口,所以只有一个配置文件​
  18. ​const config = { ... }; ​

  19. ​// 多页面,多个入口,所有有多个配置文件​
  20. ​const configs = allPages.map(page => ({​
  21. ​  // 单页面​
  22. ​  entry: `${__dirname}/src/index.js`,                 // js 入口文件​
  23. ​  // 多页面​
  24. ​  entry: `${__dirname}/src/${page}/index.js`,         // js 入口文件​
  25. ​  output: {​
  26. ​    path: `${__dirname}/dist/`,                       // 输出路径​
  27. ​    filename: '[chunkhash].js',                       // 输出文件名,这里完全取 hash 值来命名​
  28. ​    hashDigestLength: 32,                             // hash 值长度​
  29. ​    publicPath: '/dist/',​
  30. ​  },​
  31. ​  plugins: [​
  32. ​    new MiniCssExtractPlugin({                        // 提取所有的样式文件,单独打包​
  33. ​      filename: '[chunkhash].css',                    // 输出文件名,这里完全取 hash 值来命名​
  34. ​    }),​
  35. ​    new HtmlWebpackPlugin({​
  36. ​      // 单页面​
  37. ​      template: `${__dirname}/src/index.html`,        // html 入口文件​
  38. ​      // 多页面​
  39. ​      template: `${__dirname}/src/${page}/index.html`,// html 入口文件​
  40. ​      minify: {                                       // 指定如果压缩 html 文件​
  41. ​        removeComments: !0,​
  42. ​        collapseWhitespace: !0,​
  43. ​        collapseBooleanAttributes: !0,​
  44. ​        removeEmptyAttributes: !0,​
  45. ​        removeScriptTypeAttributes: !0,​
  46. ​        removeStyleLinkTypeAttributes: !0,​
  47. ​        minifyJS: !0,​
  48. ​        minifyCSS: !0,​
  49. ​      },​
  50. ​    }),​
  51. ​    new VueLoaderPlugin(),                            // vue-loader 所需​
  52. ​    new OptimizeCssAssetsPlugin({                     // 压缩 css​
  53. ​      cssProcessorPluginOptions: {​
  54. ​        preset: ['default', { discardComments: { removeAll: true } }],​
  55. ​      },​
  56. ​    }),​

  57. ​    // webpack 打包的 js 文件是默认压缩的,所以这里不需要再额外添加 uglifyjs-webpack-plugin​
  58. ​  ],​
  59. ​  module: {​
  60. ​    rules: [​
  61. ​      {                                               // js 文件加载器,与 dev 一致​
  62. ​        loader: 'babel-loader',​
  63. ​        exclude: /node_modules/,​
  64. ​        options: {​
  65. ​          presets: ['@babel/preset-env', '@babel/preset-react'],​
  66. ​          plugins: [​
  67. ​            '@babel/plugin-transform-react-jsx',​
  68. ​            '@babel/plugin-syntax-dynamic-import',​
  69. ​          ],​
  70. ​        },​
  71. ​        test: /.(js|jsx)$/,​
  72. ​      },​
  73. ​      {                                               // css 文件加载器,添加了浏览器厂家前缀​
  74. ​        use: [​
  75. ​          MiniCssExtractPlugin.loader,​
  76. ​          'css-loader',​
  77. ​          {​
  78. ​            loader: 'postcss-loader',​
  79. ​            options: {​
  80. ​              plugins: [​
  81. ​                autoprefixer({​
  82. ​                  browsers: [​
  83. ​                    '> 1%',​
  84. ​                    'last 2 versions',​
  85. ​                    'Android >= 3.2',​
  86. ​                    'Firefox >= 20',​
  87. ​                    'iOS 7',​
  88. ​                  ],​
  89. ​                }),​
  90. ​              ],​
  91. ​            },​
  92. ​          },​
  93. ​        ],​
  94. ​        test: /.css$/,​
  95. ​      },​
  96. ​      {                                               // less 文件加载器,添加了浏览器厂家前缀​
  97. ​        use: [​
  98. ​          MiniCssExtractPlugin.loader,​
  99. ​          'css-loader',​
  100. ​          {​
  101. ​            loader: 'postcss-loader',​
  102. ​            options: {​
  103. ​              plugins: [​
  104. ​                autoprefixer({​
  105. ​                  browsers: [​
  106. ​                    '> 1%',​
  107. ​                    'last 2 versions',​
  108. ​                    'Android >= 3.2',​
  109. ​                    'Firefox >= 20',​
  110. ​                    'iOS 7',​
  111. ​                  ],​
  112. ​                }),​
  113. ​              ],​
  114. ​            },​
  115. ​          },​
  116. ​          'less-loader',​
  117. ​        ],​
  118. ​        test: /.less$/,​
  119. ​      },​
  120. ​      {                                               // scss 文件加载器,添加了浏览器厂家前缀​
  121. ​        use: [​
  122. ​          MiniCssExtractPlugin.loader,​
  123. ​          'css-loader',​
  124. ​          {​
  125. ​            loader: 'postcss-loader',​
  126. ​            options: {​
  127. ​              plugins: [​
  128. ​                autoprefixer({​
  129. ​                  browsers: [​
  130. ​                    '> 1%',​
  131. ​                    'last 2 versions',​
  132. ​                    'Android >= 3.2',​
  133. ​                    'Firefox >= 20',​
  134. ​                    'iOS 7',​
  135. ​                  ],​
  136. ​                }),​
  137. ​              ],​
  138. ​            },​
  139. ​          },​
  140. ​          'sass-loader',​
  141. ​        ],​
  142. ​        test: /.(scss|sass)$/,​
  143. ​      },​
  144. ​      {                                               // 静态文件加载器,与 dev 一致​
  145. ​        loader: 'url-loader',​
  146. ​        test: /.(gif|jpg|png|woff|woff2|svg|eot|ttf|ico)$/,​
  147. ​        options: {​
  148. ​          limit: 1,​
  149. ​        },​
  150. ​      },​
  151. ​      {                                               // html 文件加载器,与 dev 一致​
  152. ​        loader: 'html-loader',​
  153. ​        test: /.html$/,​
  154. ​        options: {​
  155. ​          attrs: ['img:src', 'link:href'],​
  156. ​          interpolate: 'require',​
  157. ​        },​
  158. ​      },​
  159. ​      {                                               // vue 文件加载器,与 dev 一致​
  160. ​        loader: 'vue-loader',​
  161. ​        test: /.vue$/,​
  162. ​      },​
  163. ​    ],​
  164. ​  },​
  165. ​  resolve: {​
  166. ​    alias: {},                                        // js 配置别名   ​
  167. ​    modules: [`${__dirname}/src`, 'node_modules'],    // 模块寻址基路径​
  168. ​    extensions: ['.js', '.jsx', '.vue', '.json'],     // 模块寻址扩展名​
  169. ​  },​
  170. ​  devtool: 'source-map',                              // sourcemap ​
  171. ​  mode: 'production',                                 // 指定 webpack 为产品模式​
  172. ​}));​

  173. ​// 执行一次 webpack 构建​
  174. ​const run = (config, cb) => {​
  175. ​  webpack(config, (err, stats) => {​
  176. ​    if (err) {​
  177. ​      console.error(red(err.stack || err));​
  178. ​      if (err.details) {​
  179. ​        console.error(red(err.details));​
  180. ​      }​
  181. ​      process.exit(1);​
  182. ​    }​

  183. ​    const info = stats.toJson();​

  184. ​    if (stats.hasErrors()) {​
  185. ​      info.errors.forEach(error => {​
  186. ​        console.error(red(error));​
  187. ​      });​
  188. ​      process.exit(1);​
  189. ​    }​

  190. ​    if (stats.hasWarnings()) {​
  191. ​      info.warnings.forEach(warning => {​
  192. ​        console.warn(yellow(warning));​
  193. ​      });​
  194. ​    }​

  195. ​    // 如果是多页面,需要把 index.html => `${page}.html`​
  196. ​    // 因为每个页面导出的 html 文件都是 index.html 如果不重新命名,会被覆盖掉​

  197. ​    if(cb) cb();​
  198. ​  });​
  199. ​};​

  200. ​// 单页面​
  201. ​run(config);​

  202. ​// 多页面​
  203. ​let index = 0;​
  204. ​// go on​
  205. ​const goon = () => {​
  206. ​  run(configs[index], () => {​
  207. ​    index += 1;​

  208. ​    if (index < configs.length) goon();​
  209. ​  });​
  210. ​};​

  211. ​goon();​
2.6 analyze.js 配置

【JS】84-通用、封装、简化 webpack 配置_css

  1. ​const minimist = require('minimist');​
  2. ​const chalk = require('chalk');​
  3. ​const webpack = require('webpack');​
  4. ​const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');​
  5. ​const VueLoaderPlugin = require('vue-loader/lib/plugin');​

  6. ​const {yellow, red} = chalk;​

  7. ​const argv = minimist(process.argv.slice(2));​

  8. ​const page = argv._[0];​

  9. ​ // 单页面​
  10. ​const entryFile = `${__dirname}/src/index.js`;​
  11. ​// 多页面 ​
  12. ​const entryFile = `${__dirname}/src/${page}/index.js`; ​

  13. ​const config = {​
  14. ​  entry: entryFile,​
  15. ​  output: {​
  16. ​    path: `${__dirname}/analyze/`,                    // 打包到 analyze 目录​
  17. ​    filename: 'index.js',​
  18. ​  },​
  19. ​  plugins: [​
  20. ​    new VueLoaderPlugin(),                            // vue-loader 所需​
  21. ​    new BundleAnalyzerPlugin(),                       // 添加插件 ​
  22. ​  ],​
  23. ​  module: {​
  24. ​    rules: [​
  25. ​      {                                               // js 文件加载器​
  26. ​        loader: 'babel-loader',​
  27. ​        exclude: /node_modules/,​
  28. ​        options: {​
  29. ​          presets: ['@babel/preset-env', '@babel/preset-react'],​
  30. ​          plugins: [​
  31. ​            '@babel/plugin-transform-react-jsx',​
  32. ​            '@babel/plugin-syntax-dynamic-import',​
  33. ​          ],​
  34. ​        },​
  35. ​        test: /.(js|jsx)$/,​
  36. ​      },​
  37. ​      {                                               // css 文件加载器​
  38. ​        loader: 'style-loader!css-loader',​
  39. ​        test: /.css$/,​
  40. ​      },​
  41. ​      {                                               // less 文件加载器​
  42. ​        loader: 'style-loader!css-loader!less-loader',​
  43. ​        test: /.less$/,​
  44. ​      },​
  45. ​      {                                               // scss 文件加载器​
  46. ​        loader: 'style-loader!css-loader!sass-loader',​
  47. ​        test: /.(scss|sass)$/,​
  48. ​      },​
  49. ​      {                                               // 静态文件加载器​
  50. ​        loader: 'url-loader',​
  51. ​        test: /.(gif|jpg|png|woff|woff2|svg|eot|ttf|ico)$/,​
  52. ​        options: {​
  53. ​          limit: 1,​
  54. ​        },​
  55. ​      },​
  56. ​      {                                               // html 文件加载器​
  57. ​        loader: 'html-loader',​
  58. ​        test: /.html$/,​
  59. ​        options: {​
  60. ​          attrs: ['img:src', 'link:href'],​
  61. ​          interpolate: 'require',​
  62. ​        },​
  63. ​      },​
  64. ​      {                                               // vue 文件加载器​
  65. ​        loader: 'vue-loader',​
  66. ​        test: /.vue$/,​
  67. ​      },​
  68. ​    ],​
  69. ​  },​
  70. ​  resolve: {​
  71. ​    alias: {},                                        // js 配置别名   ​
  72. ​    modules: [`${__dirname}/src`, 'node_modules'],    // 模块寻址基路径​
  73. ​    extensions: ['.js', '.jsx', '.vue', '.json'],     // 模块寻址扩展名​
  74. ​  },​
  75. ​  mode: 'production',                                 // 指定 webpack 为产品模式​
  76. ​};​

  77. ​webpack(config, (err, stats) => {​
  78. ​  if (err) {​
  79. ​    console.error(red(err.stack || err));​
  80. ​    if (err.details) {​
  81. ​      console.error(red(err.details));​
  82. ​    }​
  83. ​    process.exit(1);​
  84. ​  }​

  85. ​  const info = stats.toJson();​

  86. ​  if (stats.hasErrors()) {​
  87. ​    info.errors.forEach(error => {​
  88. ​      console.error(red(error));​
  89. ​    });​
  90. ​    process.exit(1);​
  91. ​  }​

  92. ​  if (stats.hasWarnings()) {​
  93. ​    info.warnings.forEach(warning => {​
  94. ​      console.warn(yellow(warning));​
  95. ​    });​
  96. ​  }​
  97. ​});​
2.7 扩展配置

你可以根据需要扩展配置,比如添加插件、加载器等,比如:

  • provide-plugin 可以提供一些全局模块的导出,比如 ​​jquery​
  • define-plugin 可以动态定义一些全局变量
  • css-loader 可以配置成 css-modules
  • 如果某个页面导出 ​​js bundle​​ 很大,想分割成多个文件,可以使用 dll-plugin、split-chunks-plugin
  • 如果想在命令行显示构建的进度,可以使用 progress-plugin

3. 封装

上面的代码可以封装成一个全局命令,比如 lila,运行上面的命令就可以更简洁:

  1. ​lila dev home                               # 开发 home 页面 ​
  2. ​lila analyze explore                        # 模块分析 explore 页面 ​

  3. ​# 构建多个页面 ​
  4. ​lila build home explore about/* about/all --env test/prod​

后续

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

【JS】84-通用、封装、简化 webpack 配置_加载_02