一文彻底解决新手对 webpack 的恐惧!【下篇】

2022-05-16  本文已影响0人  懂会悟

搭建webpack项目

初始化项目
mkdir learnWebpack 
cd learnWebpack/  
# 可以输入配置  
npm init 
# 默认配置创建  
npm init -y  

# 是用npm init -y后得到的内容  
{  
  "name": "learnwebpack",  
  "version": "1.0.0",  
  "description": "",  
  "main": "index.js",  
  "scripts": {  
    "test": "echo \"Error: no test specified\" && exit 1"  
  },  
  "author": "",  
  "license": "ISC"  
}  
安装
# 我更喜欢yarn,当然你也可以使用npm  
yarn add webpack@4.44.2 webpack-cli@3.3.12 -D 
创建目录
console.log('hello webpack')    
"scripts": {  
  "test": "echo \"Error: no test specified\" && exit 1",  
  "start": "webpack"  
} 
关于警告:
ARNING in configuration The 'mode' option has not been set, webpack will fallback
 
to 'production' for this value. Set 'mode' option to 'development' or 'production' to 

enable defaults for each environment. You can also set it to 'none' to disable any 

default behavior. Learn more: webpack.js.org/configurati…

 警告中已经说的很清楚了,我们没有设置mode字段。我们只需在webpack的配置中配置mode字段即可消除该警告

关于dist文件夹和main.js文件 :这是webpack4当初宣传的零配置使用。很显然我们这里什么都没配置,就帮我们成功打包了一个src下的代码。该功能实际上是wabpack默认帮我们配置了一套简单的打包配置,让我们看看webpack默认为我们配置了什么:

默认配置
const path = require('path')  
module.exports = {  
  extry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')   
  }  
}  
webpack的零配置

上面我们看到了,零配置很弱,真正的项目中他完全不可能满足我们的需求
我们想要自定义配置webpack的话,需要在根目录上创建一个webpack.config.js的文件,这个文件的内容可以覆盖webpack的零配置

# 使用webpack.config.js配置文件时,输入该命令即可启动webpack打包  
webpack  
# 通过--config来指定其他配置文件,并按照指定的配置文件的配置内容进行打包  
webpack --config yzyConfig.js  
webpack配置核心概念

配置webpack.config.js

项目搭建目标

咱们目标不是搭建一个完整全面的项目工程,目标是以一些有代表性的功能作为切入点学习webpack,我相信这些你认真看过后一定能做到举一反三

实现加载css

我们已经知道.css文件无法正常被webpack打包进bundle(bundle的解释可查看“webpack配置核心概念”部分)文件,所以我们需要一个loader作为加载器将它正确打包进bundle文件

文件内容


安装css-loader
yarn add css-loader -D 

配置css-loader
const path = require('path')  
module.exports = {  
  entry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')  
  },  
  mode: "development",  
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: "css-loader"  
      }  
    ]  
  }  
} 

如果出现类似的error信息是因为css-loader的版本问题将css-loader版本固定即可解决

"css-loader": "3.6.0"
"style-loader": "1.3.0"

我们发现css文件的内容被成功打包了,这时如果你在dist文件夹下创建了一个html页面给div元素加上了box类,并引入main.js文件,你会发现完全看不到样式效果。

因为此时css中的内容只是被作为一段字符串引入了js中(相当于对css文件的内容进行了JSON.stringify),所以你自然是看不到效果的。

想要看到效果要怎么办?当然是将css内容放进style标签啦!不过这步不需要我们做,因为我们有style-loader为我们做这件事情!

实现css效果展示
安装style-loader (参照上面的版本)
yarn add style-loader -D

配置信息
const path = require('path')  
module.exports = {  
  entry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')  
  },  
  mode: 'development',  
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: ['style-loader', 'css-loader']  
      }  
    ]  
  }  
}    

这里需要注意的是,对同一种类型文件使用多个 loader的时候,use属性接收一个数组,并且从右向左执行。所以style-loader要写在css-loader前面
运行webpack命令,看一下结果



成功!

但是我们知道,css3在浏览器中会存在兼容性问题,我们可以通过给属性加上前缀来解决该问题。前端丰富的生态当然不会让你自己傻傻的做这件事情,我们可以通过autoprefixer这个插件帮我们完成

实现css前缀自动补充

已经知道autoprefixer是postcss工具的插件,所以我们需要安装postcss和postcss-loader

安装postcss、postcss-loader、autoprefixer,这里postcss-loader需要指定4.x的版本,因为4.x的版本和webpack4会存在报错问题

安装
yarn add autoprefixer postcss-loader@4.2.0 postcss -D  
配置
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader', 
            options: {
              postcssOptions: {  
                plugins: [require('autoprefixer')]  
              }
            }
          }
        ]
      }  
    ]  
  }

当loader需要写配置的时候,我们可以把loader写成一个对象,loader属性就是要使用的loader名称,options属性就是这个loader的配置对象。autoprefixer是postcss的插件,所以autoprefixer的使用自然就要写在postcss-loader的配置中了

因为postcss有自己的配置文件,所以这里还可以写成这样:

// webpack.config.js  
const path = require('path')  
module.exports = {  
  entry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')  
  },  
  mode: 'development',  
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: ['style-loader', 'css-loader', 'postcss-loader']  
      }  
    ]  
  }  
}  
  
// 根目录下新建postcss.config.js文件  
module.exports = {  
  plugins: [require('autoprefixer')],  
}

这里我们需要配置一下browserslist,否则插件不知道按照什么样的规则进行前缀补全

// 在package.json文件中添加  
// 这里的意思表示目标浏览器为ie浏览器,并需要兼容到ie8以上  
"browserslist": ["ie > 8"]   
postcss.jpg
实现css以文件形式导出

随着项目的增大,我们不想把那么多的样式都放在style标签中,我们想用link标签引入,这时我们就需要使用mini-css-extract-plugin
mini-css-extract-plugin 2.0.0以上版本需要webpack5

安装mini-css-extract-plugin
yarn add  mini-css-extract-plugin@2.0.0
配置
const path = require('path')  
const MiniCssExtractPlugin = require('mini-css-extract-plugin')  
module.exports = {  
  entry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')  
  },  
  mode: 'development',  
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: [  
          MiniCssExtractPlugin.loader,  
          'css-loader',  
          'postcss-loader'  
        ]  
      }  
    ]  
  },  
  plugins: [  
    new MiniCssExtractPlugin({  
      filename: "css/[name].css"  
    })  
  ]  
}  
实现自动生成html文件

我们发现dist下的html是我们自己手动创建的,这显然不够优雅。html-webpack-plugin帮你解决!

安装html-webpack-plugin,这里也要制定一下4.x的版本
yarn add html-webpack-plugin@4.5.2 -D 
配置html-webpack-plugin
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin') 
module.exports = {  
  entry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')  
  },  
  mode: "development",  
  module: { 
    rules: [
      {  
        test: /\.css$/,  
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader', 
            options: {
              postcssOptions: {  
                plugins: [require('autoprefixer')]  
              }
            }
          }
        ]
      }  
    ]  
  },
  plugins: [  
    new MiniCssExtractPlugin({  
      filename: "css/[name].css"  
    }),  
    new HtmlWebpackPlugin({  
      template: './src/index.html'  
    }) 
  ]
}

成功!很显然HtmlWebpackPlugin根据我们的模版为我们生成了新的html页面,并自动引入了dist包下的依赖。

实现打包清空dist文件夹

我们会发现每次打包dist文件夹的内容会被覆盖,但是如果下次打包出来的文件名不同,那旧的打包文件还会存在,这是我们不想要的。clean-webpack-plugin来帮我们解决这个问题

安装clean-webpack-plugin
yarn add clean-webpack-plugin -D
配置clean-webpack-plugin
const path = require('path')  
const MiniCssExtractPlugin = require('mini-css-extract-plugin')  
const HtmlWebpackPlugin = require('html-webpack-plugin')  
const { CleanWebpackPlugin } = require('clean-webpack-plugin')  
module.exports = {  
  entry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')  
  },  
  mode: 'development',  
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: [  
          MiniCssExtractPlugin.loader,  
          'css-loader',  
          'postcss-loader'  
        ]  
      }  
    ]  
  },  
  plugins: [  
    new MiniCssExtractPlugin({  
      filename: "css/[name].css",  
    }),  
    new HtmlWebpackPlugin({  
      template: './src/index.html'  
    }),  
    new CleanWebpackPlugin()  
  ]  
} 

这时,你也在dist文件夹下随意建一个其他文件,运行webpack命令看一下结果,你会发现你随意建的文件不在了。验证了这一点,就说明你成功了

实现图片在js文件中引入

实现这个功能我们使用url-loader,当然你也可以使用file-loader。url-loader是file-loader的升级版,它内部也依赖了file-loader。file-loader和url-loader在webpack5后都被废弃了,使用asset modules代替

安装url-loader和file-loader
yarn add url-loader file-loader -D   

你可能会疑问为什么要装file-loader,因为url-loader依赖file-loader。若不装,当url-loader将图片转换为base64导入bundle时不会存在问题,但直接输出图片到dist文件夹下就会报错,告诉你缺少file-loader

配置url-loader
const path = require('path')  
const MiniCssExtractPlugin = require('mini-css-extract-plugin')  
const HtmlWebpackPlugin = require('html-webpack-plugin')  
const { CleanWebpackPlugin } = require('clean-webpack-plugin')  
module.exports = {  
  entry: './src/index.js',  
  output: {  
    filename: 'main.js',  
    path: path.resolve(__dirname, './dist')  
  },  
  mode: 'development',  
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: [  
          MiniCssExtractPlugin.loader,  
          'css-loader',  
          'postcss-loader'  
        ]  
      },  
      {  
        test: /\.(png|jpe?g|gif)$/,  
        use: {  
          loader: 'url-loader',  
          options: {  
            name: '[name].[ext]',  
            limit: 1024 * 3  
          }  
        }  
      }  
    ]  
  },  
  plugins: [  
    new MiniCssExtractPlugin({  
      filename: "css/[name].css",  
    }),  
    new HtmlWebpackPlugin({  
      template: './src/index.html'  
    }),  
    new CleanWebpackPlugin()  
  ]  
}    
在入口文件中引入图片
// index.js  
import './index.css'  
import mk85 from './assets/images/mk85.jpeg'  
console.log(mk85) // mk85.jpeg  
const img = document.createElement('img')  
img.src = mk85  
const BoxDiv = document.getElementsByClassName('box')  
BoxDiv[0].appendChild(img) 

实现webpack本地服务

安装webpack-dev-server

yarn add webpack-dev-server -D  

配置

  devServer: {  
    open: true,  
    port: 8080,  
  }

小结

到这里就算是完成了一个简单的webpack项目配置,看到这里先不要着急往下看,思考一下是否真的了解了loader和plugin,如果让你写一个loader和plugin,你有思路吗
我想不出意外的话,你应该是已经有了思路。如果没有也不用担心,看看下面的内容

实现一个loader

首先loader是一个函数,注意这里不能是箭头函数
编写一个替换字符串的loader

module.exports = function (source) {  
  const result = source.replace('hello webpack', "你好呀,webpack!")  
  return result
}

使用loader

    {
        test: /\.js$/,  
        use: path.resolve(__dirname, './loader/replaceLoader.js')  
    }
实现一个plugin

同样简单,我们已经用了很多次plugin了,发现是不是都需要new一下。很显然,自定义loader是一个构造函数。
我们看一下格式:

class PluginName {  
 constructor (options) {  
 }  
 apply(compiler) {  
  ...  
 }  
}  
class HtmlPlugin {  
  constructor (options) {  
  }  
  apply(compiler) {  
   compiler.hooks.emit.tap('HtmlPlugin', (compolation) => {  
       const content = '<html><body>fake html</body></html>'  
       compolation.assets['fake.html'] = {  
         source: function () {  
           return content  
         },  
         size: function () {  
           return content.length  
         }  
       }  
     })  
  }  
 }  
 module.exports = HtmlPlugin

使用这个plugin

const HtmlPlugin = require('./plugins/html-plugin')
 plugins: [  
    new HtmlPlugin()
  ]

指纹策略

关于浏览器缓存
webpack中使用指纹策略

使用:

filename: '[name].[hash].[ext]', 

转发: 一文彻底解决新手对 webpack 的恐惧!

上一篇 下一篇

猜你喜欢

热点阅读