木灵鱼儿

木灵鱼儿

阅读:195

最后更新:2021/07/03/ 23:40:44

webpack5 初始化《JJ》主题 上部

初始化安装

yarn init

yarn add webpack webpack-cli --dev

webpack建议全局安装,省事

yarn global add webpack webpack-cli

如果不适用全局安装,直接在终端运行本项目的webpack需要使用npx命令

npx webpack -v

还有一个种办法就是在package.json创建快捷npm脚本,这样就不用加npx前缀了

{
 "scripts": {
    "build": "webpack"
  },
}

使用scss

yarn add style-loader css-loader sass sass-loader --dev

webpack.config.js

const path = require('path');
const resolve = function (myPath) {
  return path.resolve(__dirname, myPath);
};


module.exports = {
  mode: 'development',  //模式
  //入口
  entry: {
    index: './src/pages/home/index.js'
  },
  // 出口
  output: {
    path: resolve('./dist'), //指定输出目录
    filename: '[name]/index.js',  //文件名
    chunkFilename: '[id].js'
  },
  //模块-解析器loader
  module: {
    rules: [
      //css
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      // scss
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader',
        ]
      }
    ]
  }

}

如果你想要打包scss文件,你需要在入口js文件里面引入你的scss文件

import "./index.scss";

webpack在打包的时候就会处理了,但是他的处理方式是将你的js和css打包到一个js文件里,从单页角度看,还是可以的,但是我么普通项目就不需要这样,我们就可以使用一个css压缩的插件。

scss全局变量

yarn add sass-resources-loader --dev

在sass-loader之前配置sass-resources-loader

//模块-解析器loader
module: {
  rules: [
    // scss
      {
        test: /\.scss$/,
        use: [
          'cache-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          },
          'postcss-loader',
          'sass-loader',
          {
            loader: 'sass-resources-loader',
            options: {
              resources: [
                resolve("./src/assets/scss/vars.scss"),
                resolve("./src/assets/scss/mixins.scss"),
                resolve("./src/assets/scss/functions.scss"),
              ]
            }
          }
        ]
      },
  ]
}

css样式抽离-css单独保存

yarn add mini-css-extract-plugin --dev

在webpack3.x的时候用的extract-text-webpack-plugin,4和5用的这个mini-css-extract-plugin,所以,有兴趣自行百度咯!

webpack.config.js

const path = require('path');
const resolve = function (myPath) {
  return path.resolve(__dirname, myPath);
};

//样式抽离
const MiniCssExtractPlugin = require("mini-css-extract-plugin");


module.exports = {
  mode: 'development',  //模式
  //入口
  entry: {
    index: './src/pages/home/index.js'
  },
  // 出口
  output: {
    path: resolve('./dist'), //指定输出目录
    filename: '[name]/index.js',  //文件名
    chunkFilename: '[id].js'
  },
  //模块-解析器loader
  module: {
    rules: [
      //css
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      },
      // scss
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader',
        ]
      }
    ]
  },
  // 插件
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name]/style.css', //输出的css文件名,默认以入口文件名命名(例如main.css)
      chunkFilename: "[id].css", //公共样式??
    }),

  ]

}

这里就有说头了,webpack的解析器loader他是以数组的倒序开始的,也就是,最末尾设置的最开始使用,我们的scss之前的设置顺序是:

['style-loader','css-loader','sass-loader']

那么它的使用顺序就是:sass-loader -> css-loader -> style-loader

而最后执行的style-loader他的作用就是将css打包进js文件里面,所以,如果我想单独提取到css文件,就必须去掉这个解析器,使用MiniCssExtractPlugin.loader

当然单单设置解析器还不行,我们还需要启用这个插件,在plugins插件数组里面,new出这个插件,然后填入配置,具体都有注释,想了解更多可以来npm看下: mini-css-extract-plugin

css自动添加前缀

css有一些hack用法,也有一些样式需要加上浏览器的自定义前缀,那么,最求最新写法的我们,当然可能每个前缀给你记住,所以自动添加前缀是一个很有必要的措施。

yarn add autoprefixer postcss-loader --dev

autoprefixer是postcss的一个插件

postcss本身也是需要配置的,不然无法使用autoprefixer,但postcss解析器只能处理css,所以,一定要写在sass-loader前面,(顺序问题前面已经讲了)

module.exports = {
   module: {
    rules: [
      //css
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader'
        ]
      },
      // scss
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'sass-loader',
        ]
      }
    ]
  },
}

配置完这个我们还需要创建一个postcss.config.js文件,这个文件与webpack.config.js同级。

postcss.config.js

module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}

除了这个还需要创建一个兼容浏览器的配置文件.browserslistrc,也是同级。

我们可以在vue cli项目上看到这个文件,所以,照抄就行了

.browserslistrc

> 1%
last 2 versions
not dead

然后我们可以尝试打包一些这段css测试一下:

@media (min-resolution: 2dppx) {
  .image {
    background-image: "";
  }
}

打包后应该会编译为:

@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
  .image {
    background-image: "";
  }
}

功能没问题

更强的css处理

yarn add postcss-preset-env --dev

postcss-preset-env可以做到autoprefixer的功能,还能更强,他可以将现代的css转换成浏览器能解析的内容,除了添加浏览器前缀,还能解析16进制的颜色(谷歌f12控制台查看css,部分颜色是16进制了),还能根据目标浏览器或者运行时环境添加所需的polyfill。

总之强就对了,开搞

postcss.config.js

module.exports = {
  plugins: [
     require('postcss-preset-env')
  ]
}

这样完事,你可以在css里面测试一下

@media (min-resolution: 2dppx) {
  .image {
    background-image: #12321313;
  }
}

打包后应该会编译为:

@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
  .image {
    background-image: rgba(18,50,19,0.07451);
  }
}

完美。

处理css中的 @import属性问题

在传统css中使用@import他是一个原生功能,引入另一个css文件,但是,如果你在css中使用@import,被引入的那个文件并不会经过postcss的处理,它属于css语法,所以,能处理到被引入的文件只有: css-loader、style-loader、MiniCssExtractPlugin.loader

style-loader我们弃用了,所以能处理解析器是:css-loader

解决方法:

module.exports = {
   module: {
    rules: [
      //css
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          },
          'postcss-loader'
        ]
      },
      // scss
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          },
          'postcss-loader',
          'sass-loader',
        ]
      }
    ]
  },
}

css-loader中importLoaders表示impor引入文件要用哪个已经配置的解析器处理,0表示它自身,1表示往后倒一位,就是postcss-loader

如果postcss-loader在后几位,就对应加上

{
    test: /\.scss$/,
    use: [
        MiniCssExtractPlugin.loader,
        {
            loader: 'css-loader',
            options: {
                importLoaders: 3
            }
        },
        'xxxx-loader',
        'xxxx-loader',
        'postcss-loader',
        'sass-loader',
    ]
}

注意:

css的@import引入并不会按照引入语法的位置引入css。

@import "xxx.css";  //或者 @import url("xxx.css");

使用这种写法,引入的css文件会作用在最开头;

div {
  color:#000;
}

@import "color.css";

color.css

div {
  color: red;
}

按我们的写法,我们希望的是color.css发挥作用,但是实际情况是这样的:

div {
  color: red;
}

div {
  color:#000;
}

所以,用的时候需要注意。

css压缩

MiniCssExtractPlugin推荐使用css-minimizer-webpack-plugin来压缩css

yarn add css-minimizer-webpack-plugin --dev

npm地址:css-minimizer-webpack-plugin

在webpack的优化选项中使用

//css压缩
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  //优化
  optimization: {
    minimize: true, //开发模式也压缩代码
    minimizer: [
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: 'advanced', // 需额外安装
        },
      }),
    ]
  }
}

advanced这个功能用于移除未使用的css,但是需要额外安装一个插件:

yarn add cssnano-preset-advanced  --dev

除了advanced模式,还有default和lite模式,具体可以去查查了,能用就行。

注意:如果不开启minimize: true,那么代码在开发模式就不会压缩,除非你将mode模式改为生产模式:production

webpack.config.js

module.exports = {
  mode: 'production',
}

每次打包前删除dist

由于每次打包,其实是文件的覆盖,如果打包的时候,有一个文件没有了,但是上一次打包存在的,那么就会产生文件残留,所以,我们需要再每次打包的时候,先清理掉dist再重新生成。

yarn add clean-webpack-plugin --dev

webpack.config.js

//清理打包文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  // 插件
  plugins: [
    //清理打包文件
    new CleanWebpackPlugin(),
  ]
}

这样即可。

javascript配置babel

yarn add @babel/core babel-loader @babel/preset-env --dev

webpack.config.js

module.exports = {
  module:{
    rules:[
      // js
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
}

完成

压缩javascript

babel配置完毕后,我们还需要处理js的压缩,默认webpack5自动安装了TerserPlugin插件,其他版本则需要手动安装,我们webpack5直接引入并使用即可。

//js压缩
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  //优化
  optimization: {
    minimize: true, //开发模式也压缩代码
    minimizer: [
      //js压缩优化
      new TerserPlugin({
        parallel: true, // 可省略,默认开启并行
        terserOptions: {
          toplevel: true, // 最高级别,删除无用代码
          ie8: true,
          safari10: true,
        }
      })
    ]
  }
}

minimize: true的理由也是和css一样,开发模式,代码是不会进行压缩处理的,需要配置这个查看效果。

处理LICENSE文件

开启压缩后,会生成xxx.LICENSE.txt文件,这个文件用于存放注释用的,压缩时会将所有的注释提取到保存成这种文件,如果不想生成,我们可以关闭该功能。

//js压缩
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  //优化
  optimization: {
    minimize: true, //开发模式也压缩代码
    minimizer: [
      //js压缩优化
      new TerserPlugin({
        parallel: true, // 可省略,默认开启并行
        terserOptions: {
          toplevel: true, // 最高级别,删除无用代码
          ie8: true,
          safari10: true,
        },
        extractComments: false, //关闭生成LICENSE文件
      })
    ]
  }
}

稍微优化那么一丢丢babel

// js
{
  test: /\.m?js$/,
  exclude: /(node_modules|bower_components)/,  // 不处理该文件夹下的js文件
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env'],
    }
  },
}

/\.m?js$/官方说可以编辑更少的文件,但是会导致加载到node_modules目录,所以我们后面exclude黑名单中将一些不需要编译的目录设置了。

路径别名

这个还是很重要的

webpack.config.js

module.exports = {
  //解析器
  resolve: {
    alias: {
      '@': resolve('./src')
    }
  }
}

resolve方法在最上面就定义过了,这里就省略书写了。

代码分割-拆包

  • 把多个页面共用的第三方库(比如React,Fastclick)单独打包出一个vendor.js
  • 把多个页面共用的逻辑代码和共用的全局css(比如css-reset,icon字体图标)单独打包出common.jscommon.css
  • 把运行时代码单独提取出来manifest.js
  • 把每个页面自己的业务代码打包出page1.jspage1.css

webpack.config.js

module.exports = {
  //优化
  optimization: {
   //拆包
    splitChunks: {
      chunks: 'async',
      cacheGroups: {
        // 打包第三方库的文件
        vendors: {
          name: `vendor`,
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          chunks: 'initial',
          // minChunks: 2, // 同时引用了2次才打包
        },
        // 打包业务中公共代码
        common: {
          name: `common`,
          minChunks: 2,  // 同时引用了2次才打包
          priority: -20,
          chunks: 'initial',
          reuseExistingChunk: true
        }
      }
    },
    runtimeChunk: { name: 'manifest' } // 运行时代码
  }
}

实际效果就是:

node_modules中安装的库,在被两次引用后会打包到vendor的文件内;

而多次使用的js代码和css代码会被提取到common中。

剩下的就是各归各的了。

区分下生产和开发模式

做一个简单的效果区分,在开发模式下,我们关闭代码压缩,在生产模式下,我们开启代码压缩和map文件文件生成。

官方示例上有一个很简单的办法,省的安装cross-env来配置环境变量了,windows的痛。

webpack --mode=development

如果要获取,那么webpack.config.js就必须导出一个方法用于接收参数。

module.exports = (env, argv) => ({
  mode: argv.mode || 'development',  //模式 development、production
  devtool: argv.mode === 'production' ? 'source-map' : 'eval',
})

记得关闭optimization下的minimize属性。

然后我们在package.json里面配置两个命令

{
  "scripts": {
    "dev": "webpack --mode=development",
    "build": "webpack --mode=production"
  },
}

运行dev则是开发模式

运行build则为生产模式

watch监听文件

基本上的东西都配置好了,但是每次修改一次文件就要运行一次太累了,我们希望他能自动监听文件的变化,自动打包生成文件。

webpack.config.js

module.exports = (env, argv) => ({
  // 监听
  watch: argv.mode === 'development',  //开发模式监听
  //监听的配置
  watchOptions: {
    aggregateTimeout: 600,  //延迟600ms打包
    ignored: /node_modules/,  //忽略
  }
})

ignored可以忽略监听一些内容过多的文件夹,多个就用数组,可以用正则匹配

代码分析

分析有时候还有有必要的,看看自己的文件打包后大小,什么东西占据最大的部分啥的,有利于优化。

yarn add webpack-bundle-analyzer --dev

由于webpack默认在生产模式会开启concatenateModules,导致分析不完整,所以我们还需要在分析模式关闭这个配置,但是我们必须判断运行的命令是否为分析模式,所以,我们还是需要安装cross-env

yarn add cross-env --dev

package.json

"scripts": {
    "dev": "webpack --mode=development",
    "build": "webpack --mode=production",
    "analyzer": "cross-env ANALYZER=true webpack --mode=production"
  },

analyzer为分析命令,分析肯定还是要在生产模式下的。

webpack.config.js

//分析
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = (env, argv) => ({
  // 插件
  plugins: [
     //代码分析
    (process.env.ANALYZER && new BundleAnalyzerPlugin({
      analyzerMode: "static",  //生成静态文件
    })),
  ],
  //优化
  optimization: {
    concatenateModules: process.env.ANALYZER ? false : true,  //分析模式禁用他,不然分析不全面
   }
})

基本就这样。

我们设置生产静态文件,不然默认设置会开启一个http服务,挺烦的,还需要手动关闭,还是生成静态文件方便一些。

yarn remove @babel/plugin-transform-modules-commonjs @babel/plugin-transform-runtime @babel/runtime @babel/runtime-corejs3

使用cache-loader加速编译

yarn add cache-loader --dev
module.exports = (env, argv) => ({
   //模块-解析器loader
  module: {
    rules: [
      //css
      {
        test: /\.css$/,
        use: [
          'cache-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          },
          'postcss-loader'
        ]
      },
      // scss
      {
        test: /\.scss$/,
        use: [
          'cache-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          },
          'postcss-loader',
          'sass-loader',
        ]
      },
      // js
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,  // 不处理该文件夹下的js文件
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            cacheDirectory: true, //开启缓存
          }
        },
      }
    ]
  },
});

全局jquery

如果是普通使用jq,只需要安装后import引入即可。

yarn add jquery --dev

使用

import $ from "jquery";

$(function () {
  console.log(111);
}) 

如果要使用插件啥的,可能还需要丢入全局

yarn add expose-loader  --dev

然后再webpack.config.js中配置一下

module.exports = (env, argv) => ({
  //模块-解析器loader
  module: {
    rules: [
      // jquery
      {
        test: require.resolve('jquery'),
        loader: 'expose-loader',
        options: {
          exposes: ['$', 'jQuery'],
        },
      },
    ]
  }
})

版权申明

本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。

关于作者

站点职位 博主
获得点赞 0
文章被阅读 195

相关文章