记一次webpack4.x项目配置

在自构建自己的个人页面的时候使用到webpack4,遇到了一些问题,查看了大佬们的文章以及官方文档,在这里总结一下。

webpack比较基础的东西就不赘述了,代码里面的注释也会辅助说明,先看一下目录结构:

│  .babelrc
│  .gitignore
│  package-lock.json
│  package.json
│  README.en.md
│  README.md
│      
├─build
│      webpack.common.js
│      webpack.dev.js
│      webpack.prod.js
│      webpack.rules.js
│                
└─src
    ├─assets
    │      test.json
    │      
    ├─common
    │  ├─css
    │  ├─fonts
    │  ├─images
    │  └─js
    └─pages
        ├─my
        │      index.html
        │      index.js
        │      index.styl
        │      
        └─other
                index.html
                index.js
                index.styl
                

这里目录结构导出如果有不知道的同学,其实很简单,windows命令 tree /f 导出当前目录包括文件夹名字,tree /f > catalog.txt 导入到一个txt文本。

1.webpack整体配置

像大部分同学的习惯一样,在build文件夹里面分为几个webpack配置,common基础公用配置,dev开发环境配置,prod生产环境配置,以及单独分离出来的rule配置各项loader。

//common
module.exports = (env) => {
  return {
    entry: {},
    plugins: [],
    optimization: {},
    module: {}
  }
};
//dev
module.exports = merge(common('development'), { mode: 'development', devtool: 'inline-source-map', output: {}, devServer: {}, plugins: [], });
//prod
module.exports = merge(common('production'), { mode: 'production', output: {}, plugins: [ ], });

这里webpack4 推荐用mode声明开发环境还是生产环境,这里是作为一个全局变量,而不是node环境,所以如果要在配置里面用到全局变量,用函数返回

这里我是直接定义的变量,然后在引用的时候传入参数,不是官方所定义的全局变量,其实这样写不是很好,既然分离了环境那就应该在不同的配置文件中写配置。

2.多页面entry配置和html模版插件

webpack里面的entry

    entry: {
      // 多入口文件
      my: [
        './src/pages/my/index.js',
      ],
      other: [
        './src/pages/other/index.js',
      ]
    },

在外部定义多个页面的信息,以及html-webpack-plugin模版插件的函数进行批量操作

/*可多页面配置*/
const htmlArray = [
  {
    _html: 'my',
    title: '我的首页',
    // chunks: ['my']
  },
  {
    _html: 'other',
    title: '其他',
    // chunks: ['other']
  }
];
// 获取html-webpack-plugin参数的方法
let getHtmlConfig = function (name, title, globalEnv) {
  return {
    template: `./src/pages/${name}/index.html`,
    filename: `${name}.html`,
    // favicon: './favicon.ico',
    title: title,
    inject: true,
    hash: false, //开启hash  ?[hash]

    /*chunk 里面配置的文件才会在html中引入,所以有其他引入的话要注意加上,
    比如runtime和splitChunks里面的vendor等,建议不要这个,默认加载所有的*/
    // chunks: chunks,

    minify: globalEnv === "development" ? false : {
      removeComments: true, //移除HTML中的注释
      collapseWhitespace: true, //折叠空白区域 也就是压缩代码
      removeAttributeQuotes: true, //去除属性引用
    },
  };
};

在webpack plugin里面引入执行html模版

      //自动生成html模板
      ...htmlArray.map((element) => {
        return new HtmlWebpackPlugin(getHtmlConfig(element._html, element.title, env));
      }),

3.module.rules loader加载器

由于loader比较多,可以单独提取到一个配置文件

    css,css预处理器loader,MiniCssExtractPlugin是webpack4分离css的插件,后面再提到

  1.     {
          test: /\.(css|styl)$/,
          // 区别开发环境和生成环境
          /*用了MiniCssExtractPlugin,不要用style-loader,冲突*/
          use: env === "development" ?
            ["style-loader", "css-loader", "stylus-loader"] :
            [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"]
        },
  2.     {
          test: /\.js$/,
          exclude: "/node_modules/",
          use: [{
            loader: "babel-loader",
            options: {
              /*可使用禁止在每个文件注入runtime,避免文件多而大,采用babel-plugin-transform-runtime辅助提取引用
               *  plugins: ['@babel/transform-runtime']*/
    
              // 配置在 .babelrc 中,和browserslist
              // presets: ['@babel/preset-env']
            }
          }]
        },

    这里是base64转换和输入位置,更多配置可以看官网

  3.     {
          test: /\.(png|jpg|gif)$/,
          use: [{
            // url-loader包含file-loader
            loader: "url-loader",
            options: {
              limit: 5 * 1024, //小于5k时将会已base64位图片打包处理
              // 图片文件输出的文件夹
              outputPath: "images"
            }
          }]
        },

    字体和html的 loader

  4.     {
          test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
          loader: 'url-loader',
          options: {
            limit: 10000,
            /*原来的名字和后缀*/
            name: '[name].[ext]',
            // 文件输出的文件夹
            outputPath: "fonts"
          }
        },
        {
          test: /\.html$/,
          // html中的img标签
          use: ["html-withimg-loader"]
        },

4. plugin

common 里面,第一个是html模版,上面讲过了,第二三个顾名思义。

    plugins: [

      //自动生成html模板
      ...htmlArray.map((element) => {
        return new HtmlWebpackPlugin(getHtmlConfig(element._html, element.title, env));
      }),

      // 消除冗余的css代码
      new PurifyCssWebpack({
        paths: glob.sync(path.join(__dirname, "../src/pages/*/*.html"))
      }),

      //静态资源输出
      new CopyWebpackPlugin([{
        from: path.resolve(__dirname, "../src/assets"),
        to: './assets',
        ignore: ['.*']
      }]),


    ],

dev,这里官方提示使用这里完全启发devServer热更新,我没深入研究,同志们可以研究一下。

  plugins: [
    //热更新,配合devserver服务完全启动HMR
    new webpack.HotModuleReplacementPlugin(),

    // new BundleAnalyzerPlugin(),     //性能优化 高大上的可视化分析模块
  ],

prod,清理dist的插件有一点小变动,提取css的插件官方建议被替代,以及仍然需要额外的插件压缩css

  plugins: [

    /*删除dist目录,2.0后默认了output的path,这里无需填写*/
    new CleanWebpackPlugin({
      root: path.resolve(__dirname, '../'), //根目录
      // verbose Write logs to console.
      verbose: true, //开启在控制台输出信息
    }),

    /*webpack用这个代替ExtractTextPlugin,提取,开发环境我没分离*/
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: '[name].[contenthash].css',
      // chunkFilename: '[id].[contenthash].css',
    }),
    //压缩css
    new OptimizeCSSPlugin(),

  ],

5. 代码压缩和分离

    /*代码分离 压缩,webpack4x集成部分插件和选项*/
    optimization: {
      /*压缩js代码入口,是否开启minimizer,
       例如TerserWebpackPlugin插件,性能比UglifyJSPlugin好
       默认引入生产模式为true,所以不用操作,可以手动开启和调节minimizer选项*/
      // minimize: false

      /*将运行时代码拆分为单独的块。
       将其设置single为为所有块创建单个运行时包
       单页面
       runtimeChunk: 'single',
       */

      /*多页面别名*/
      runtimeChunk: {
        name: entryPoint => `runtimechunk~${entryPoint.name}`
      },
      /*分离公共代码*/
      splitChunks: {
        /*缓存chunk 提取公共模块复用*/
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all'
          }
        }
      },
    },

6. 开发环境devServer

  devServer: {
    contentBase: path.join(__dirname, "../dist"),
    publicPath:'/',
    host: "127.0.0.1",
    port: "5199",
    overlay: true, // 浏览器页面上显示错误
    // open: true, // 开启浏览器  open: 'Google Chrome'
    // stats: "errors-only", //stats: "errors-only"表示只打印错误:
    hot: true, // 开启热更新
    // compress: true,   //开启gzip
  },

7. 生产环境 output 输出

  output: {
    path: path.resolve(__dirname, '../dist'),
    // 打包多出口文件
    // 生成 a.bundle.[hash].js  b.bundle.[hash].js
    // hash工程级整个是一样的,chunkhash模块级有依赖的文件是一样的,contenthash根据自身的内容生成hash,每个文件都不一样
    filename: './js/[name].[contenthash].js',
    publicPath: './'
  },

 8. js 语法和api转换编译

  开发依赖

"@babel/cli": "^7.2.3",
"@babel/core": "^7.3.4",
"@babel/plugin-transform-runtime": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"babel-loader": "^8.0.5",

生产也需要的依赖
"dependencies": {
"@babel/polyfill": "^7.2.5",
"@babel/runtime": "^7.3.4"
}
其中runtime官方的说法是节约代码以及生成器语法的转换,如果不用这两个使用async和await会报错。

然后在.babelrc中使用,关于 @babel/polyfill 的使用,这里配合 @babel/preset-env 有三种使用方式,这里usage会自动根据代码转换,安装后不要引入。

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage"
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

 最后在package.json或者单独建立browserslist文件来限制浏览器版本和转换操作

"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
],




最后启动和大概测试了下,没发现什么问题。
由于时间和能力有限,可能有很多没考虑到,不够深入理解,还有一些冗余甚至错误的地方望各位大佬指正。

参考:

1,多页面配置,参考的是这位大佬的文章。https://segmentfault.com/a/1190000014984842

2,webpack官方文档,可以统一看一遍。https://webpack.js.org/plugins/mini-css-extract-plugin/

3,babel相关官方文档  https://babeljs.io/docs/en/babel-polyfill#docsNav

附:

1,在线配置webpack的页面,常用的依赖,插件和代码分割以及安装命令等。https://webpack.jakoblind.no/

time:2019-02-15

猜你喜欢

转载自www.cnblogs.com/caelan/p/10527635.html