webpack脚手架基础能力搭建(一)

285 阅读6分钟

本文将通过介绍webpack的核心模块,让开发人员具备搭建脚手架的底层基础能力,并能快速上手。首先通过一张图看懂webpack的构建流程以及需要具备的核心知识点。

1、准备

在控制台中输入以下代码,创建示例工程

//创建项目根目录
mkdir demo-cli && cd demo-cli
//初始化项目
npm init

一路确认,直到完成。再安装两个核心插件:

1、webpack核心包

npm i webpack -D

2、webpack-cli包

npm i webpack-cli -D

新建src和public文件夹,分别用于存放源代码和静态资源,并初始化创建src/index.js和public/index.html文件。完成后项目结构如下:

2、环境定义

webpack对环境有明确的定义,可通过mode参数配置:

  • development:代表开发环境,当配置为该值时,webpack需配合webpack-dev-server插件使用,在本地启动服务器,用于开发和调试代码。
  • production:代表生产环境,当配置为该值时,webpack会对所有的html和js进行编译构建,并输出到指定的路径,用于发布到生产环境。

项目根目录新建build文件夹,用于存放webpack构建脚本。新建如下文件:

  • webpack.dev.js:开发环境配置
  • webpack.prod.js:生产环境配置
  • webpack.base.js:公共配置

完成本步骤后项目结构如下:

3、配置入口和出口

webpack通过entry配置,找到入口文件,开始解析文件并构建AST语法树,找到依赖,并递归下去,经过一系列编译后通过output配置,输出到指定路径下。

在webpack.base.js中配置如下:

const path = require('path')

module.exports = {
  //入口配置
  entry: {
    //入口文件
    'index': './src/index.js'
  },
  //出口配置
  output: {
    //编译后的文件输出目标路径
    path: path.resolve(__dirname, '../dist'),
    //编译后的输出文件名
    filename: '[name].[hash].js',
    //在dist中输出的html文件中引入的css和js文件路径前面那串字符串
    publicPath: ''
  }
}

安装html-webpack-plugin插件,该插件用于生成html文件,并在body中通过script标签引入所有webpack构建后的bundle。如果使用了样式抽离插件(mini-css-extract-pulugin),样式文件也会通过link标签在html中引入。

npm i html-webpack-plugin -D

并在webpack.base.js中追加以下配置

...
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  ...
    //插件配置
    plugins: [
    //生成一个html文件,并在该文件中通过script标签引入所有webpack构建后的bundle
    //如果使用了mini-css-extract-plugin抽离样式文件,也会在该文件中通过link标签引入css文件
    new HtmlWebpackPlugin({
      //html模板文件位置
      template: './public/index.html',
      //生成的html文件名
      filename: 'index.html',
      //生成的index.html引用的文件,这里设置的是entry中的key
      chunks: ['index']
    })
    ]
}

因为区分了webpack.dev.js和webpack.prod.js分别配置开发环境和生产环境的构建脚本,因此需要安装webpack-merge插件,该插件用于合并配置脚本。

npm i webpack-merge -D
  • webpack.dev.js 改造如下:
const path = require('path')
const base = require('../build/webpack.base.js')
const { merge } = require('webpack-merge')

module.exports = merge(base, {
  //定义环境
  mode: 'development',
  //定义开发服务
  devServer: {
    //本地静态资源文件文件夹,用来配置该文件夹内的静态资源支持http访问
    static: [
      //本地public路径
      path.resolve(__dirname, './public'),
      //构建目标路径
      path.resolve(__dirname, './dist')
    ],
    //本地启动服务后的访问IP
    host: 'localhost',
    //本地启动服务后的访问端口
    port: 8080,
    //服务启动后自动打开浏览器
    open: true,
  }
})

然后在package.json文件中配置启动命令。

“serve”: "webpack serve --config webpack build/webpack.dev.js --color --progress --hot"

安装webpack-dev-serve用于启动本地服务

npm i webpack-dev-server -D

配置并安装完相关插件后,可以在控制台尝试启动本地服务

npm run serve

浏览器自动打开,并在控制台输出打印日志,则说明开发环境配置正常。

  • webpack.prod.js 改造如下:
const path = require('path')
const base = require('../build/webpack.base.js')
const { merge } = require('webpack-merge')

module.exports = merge(base, {
  //定义环境
  mode: 'production'
})

然后在package.json文件中配置生产命令

"build": "webpack --config build/webpack.prod.js --color --progress"

尝试在控制台执行构建命令

npm run build

构建完成后,在dist目录下生成了js和html文件,则说明生产构建成功。

4、样式处理

我们通过以下loader来处理样式:

  • style-loader:通过js脚本创建style标签,里面包含一些样式
  • css-loader:识别css文件,通过特定语法识别并导出内容,导出内容格式为数组,页面并不能直接使用
  • postcss-loader:处理样式浏览器兼容性,自动补全样式前缀,
  • sass-loader:编译解析scss样式
npm i style-loader css-loader postcss-loader sass-loader sass -D

定义postcss的配置文件,这里需要依赖postcss,postcss-preset-env,cssnano插件

npm i postcss postcss-preset-env cssnano -D

然后定义postcss.config.js文件,并配置如下:

module.exports = {
  plugins: {
    'postcss-preset-env': {},//处理兼容性
    'cssnano': {} //压缩样式
  }
}

修改index.html页面,增加样式代码案例如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>webpack脚手架基础构建能力</title>
  </head>
  <body>
    <div>我是index.html</div>
    <div class="item-box">
      <div class="item">我是item一</div>
      <div class="item">我是item二</div>
    </div>
  </body>
</html>

创建scss文件,内容如下:

// src/css/main.scss.item-box{
  display:flex;
  justify-content: center;
  align-items: center;
  .item{
    color: #ffffff;
    width: 100px;
    height: 100px;
    background-color: #00a0e4;
  }
}

然后在index.js中通过import引入scss文件

  • webpack.dev.js改造 ,追加loader解析命令
...

module.exports = merge(base, {
  ...
    //配置loader规则
    module: {
  rules: [
    //编译本地css文件
    {
      test: /.css$/,
      use: [
        {loader: 'style-loader'},
        {loader: 'css-loader'},
        {loader: 'postcss-loader'}
      ]
    },
    //编译本地scss文件
    {
      test: /.scss$/,
      use: [
        {loader: 'style-loader'},
        {loader: 'css-loader'},
        {loader: 'postcss-loader'},
        {loader: 'sass-loader'}
      ]
    }
  ]
}
})

尝试启动项目

npm run serve

可以通过浏览器控制台查看css样式是否补全了前缀,以此验证loader是否处理成功。

生产环境和开发环境对样式的处理是不一样的,开发环境webpack是启动的本地服务器,可将样式内联在js中,但生产环境一般需要抽离成单独的css文件,以避免单个js文件过大,影响加载性能。因此需要用到mini-css-extract-plugin插件来抽离样式文件

npm i mini-css-extract-plugin -D
  • webpack.prod.js 改造,追加以下配置:
...
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = merge(base, {
  ...
    //配置loader规则
    module: {
  rules: [
    //编译本地css文件
    {
      test: /.css$/,
      use: [
        MiniCssExtractPlugin.loader,
        {loader: 'css-loader'},
        {loader: 'postcss-loader'}
      ]
    },
    //编译本地scss文件
    {
      test: /.scss$/,
      use: [
        MiniCssExtractPlugin.loader,
        {loader: 'css-loader'},
        {loader: 'postcss-loader'},
        {loader: 'sass-loader'}
      ]
    }
  ]
},
plugins: [
  //配置样式抽离插件,生成的css文件名为[name],[name]为entry中定义的key
  new MiniCssExtractPlugin({
    filename: "[name].[hash].css"
  })
]
})

然后我们运行

npm run build

查看生成的dist文件夹是否生成了css文件,并在html中通过link外部引用。

细心的小伙伴会发现,每次构建build命令,dist目录会有很多历史文件,这时需要用到clean-webpack-plugin插件,用于清除dist目录的文件

npm i clean-webpack-plugin -D

在webpack.prod.js中追加如下内容

...
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = merge(base, {
  ...
    plugins: [
    ...
    //配置清除dist目录的插件
    new CleanWebpackPlugin()
    ]
})

然后我们运行

npm run build

dist目录下只保留了最新生成的文件。

到这里,我们已初步完成脚手架核心能力搭建

在下一节,我们将继续完善脚手架底层能力:

  • js编译与解析
  • 文件处理
  • source-map的处理
  • 路径解析处理