webpack 实战(1) - 入门篇

463 阅读3分钟

[toc]

webpack 这篇专栏文章介绍了 webpack 的概念与基础用法,并且介绍了常用的实际应用场景,相信看完后就可以搭建一套自己的 web 构建程序。

1 概念

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

2 基础配置属性介绍

2.1 entry

打包的入口文件,打包时会根据入口文件找到项目的依赖,形成一棵依赖树。

2.1.1 单入口:

一个应用只有一个入口,适合单页应用。

module.exports = {
  entry: './src/index.js'
}

2.1.2 多入口:

适合多页面应用,entry 是一个对象

module.exports = {
  entry: {
      app: './src/index.js',
      home: './src/home.js',
  }
}

2.2 output

设置打包的出口

参数:

  • path: 打包后的文件目录。
  • filename:打包后的文件名字。可以用 [name] 的形式对文件名占位
var path = require('path');
module.exports = {
  entry: {
    index: './src/index.js',
    home: './src/home.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
  }
}

2.3 loaders

webpack 本身只支持 js 和 json 两种文件类型,通过 loaders 去支持其他文件类型并且可以添加到依赖树中,比如 html、jsx、css、图片等。loaders 本身是一个函数,将文件输入并转换出想要的文件。

2.3.1 用法

参数:

  • test:匹配规则
  • loader:loader 名字
  • exclude:排除规则
  • query | options: loader 参数
modules.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader'
      },
      { test: /\.tsx?$/,
        loader: 'ts-loader'
      },
      {
        test: /\.js?$/,
        exclude: /(node_modules|packages)/,  // 排除的目录
        loader: 'babel-loader',
        query: {presets: ['es2015', 'react']}} // 配置参数
    ]
  },
};

2.3.2 常用的 loader

  • babel-loader:转换es6、es7等新js语法
  • css-loader: 支出 css 的加载解析,在页面中可以通过 import 的方式将 css 引入页面
  • scss-loader:将 less 文件转换成 css
  • ts-loader: 将 ts 转换为 js
  • file-loader:进行图片、字体等文件的解析
  • url-loader: 内置了 file-loader,可以设置 ‘limit’,当文件体积小于 limit 的时候将文件转成 DataURL,当大于 limit 的时候调用 file-loader 处理。
  • raw-loader:将文件以字符串的形式导入
  • thread-loader:使用多进程打包,用于打包速度优化处理耗时 loader
  • cache-loader: 将其后面 loader 打包的结果缓存到磁盘

2.4 plugins

插件。打包过程中文件处理的一部分,添加打包过程中的各种功能。

2.4.1 用法

modules.exports = {
  entry: {
      index: './src/index.js'
  },
  plugins: [
    new HtmlWebpackPlugin({template: './index.html'})
  ],
};

2.4.2 常用的 plugins

  • Webpack-dev-server: 是一个express服务器,提供项目运行服务(自带热更新)
  • CommonsChunkPlugin:将公用的js提取出来作为独立的的模块,webpack4.0中被 SplitChunksPlugin 替代
  • CleanWebpackPlugin:清理构建目录
  • ExtractTextWebpackPlugin:将 css 从 bundle 中提取出来作为独立的文件
  • HtmlWebpackPlugin: 创建 html 文件并将打包后的文件插入进去
  • speed-measure-webpack-plugin 构建时会列出各个 loader 和 plugin 消耗时间信息,可用于分析优化策略
  • Happypack:使用多进程打包,用于打包速度优化

2.5 model

指定当前环境

值:

  • production:线上环境。自动开启FlagDependencyUsagePlugin、FlagIncludeChunksPlugin、ModuleCocatenationPlugin、NoemitOnErrorsPlugin、OccurrenceOrderPlugin、SideEffectsFlagPlugin、TerserPlugin。自动对代码进行压缩、识别打包时副作用的参数等。
  • development:开发环境。自动开启 NamedChunksPlugin、NamedModulesPlugin。在 HMR 阶段在控制台打印更新的目录。
  • none:不开启任何优化选项。
modules.exports = {
  mode: 'production',
};

3 实际应用

3.1 以 npm 命令的形式运行 webpack

webpack 的运行命令一般比较长,如果参数比较多的话会更长,可以把 webpack 以 npm 命令的方式执行

  1. 将命令配置在 package.json
{
    "scripts": {
        "build": "webpack --config=./webpack.config.js",
    }
}
  1. 使用的时候直接运行 npm run build

3.2 利用 babel 解析 es6 和 '.jsx'

需要用到 babel-loader, 上面说过 loader 是用来处理输入文件然后转义成想要的输出文件的,这里以 转义 es6 语法 与 react .jsx 语法为例。转义其他类型的文件如 .scss 方式雷同,只不过 loader 与配置参数不一样

  1. 下载 babel 相关依赖
npm i -D @babel/core @babel/preset-env babel-loader
  1. 创建 babel的配置文件 .babelrc(更多 babel 相关配置请看 babel 文档)
{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}
  1. 配置 webpack.config.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.js(x?)$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                }
            },
        ],
    },
};

注: babel-loader 还支持不使用 .babelrc ,直接在 babel-loader 的参数中配置 babel, 下面的方式与上面的效果一样

module.exports = {
    module: {
        rules: [
            {
                test: /\.js(x?)$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                    query: {
                        presets: ['env', 'react'],
                    }
                }
            },
        ],
    },
};

3.3 将 js 自动以 <script/> 的形式插入 html

这里介绍的是 Plugin 的实际应用(plugin 的作用上面介绍过了),本示例中会用到 HtmlWebpackPlugin

  1. 下载 HtmlWebpackPlugin
npm i -D html-webpack-plugin
  1. webpack.config.js 中引入并使用

每个模板页必须单独配置 HtmlWebpackPlugin,如果有多个页面就得使用多个 HtmlWebpackPlugin, 下面示例配置了 'index' 与 'home' 两个文件的模板。

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

module.exports = {
    entry: {
        index: './src/index/index.jsx',
        home: './src/home/home.jsx'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name]/[name].[chunkhash:8].js'
    },
    plugins: [
        new HtmlWebpackPlugin({
            chunks:['index'],  // 说明要加载的模块(不指定的话,index.js 与 home.js 都会引进来)
            filename: 'index/index.html', // 输出位置与名字
            template: 'src/index/index.html'  // 模板位置
        }),
        new HtmlWebpackPlugin({
            chunks:['home'],
            filename: 'home/home.html',
            template: 'src/home/home.html'
        }),
    ],
}

: 更多配置,请看 HtmlWebpackPlugin 文档

3.4 将 css 与 js 分离,并插入 html

默认 webpack 在打包的时候会将 css 打包进引用的 bundle.js 中, 我们可以用 ExtractTextWebpackPlugin 将 css 分离出来,以实现 js、html 与 css 的分离,与通用 css 复用的目的。下面的例子顺便介绍了 sass 的转译

  1. 下载 css 相关 loader 与 ExtractTextWebpackPlugin
npm i -D css-loader sass-loader extract-text-webpack-plugin
  1. webpack.config.js 配置
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');

module.exports = {
    module: {
        rules: [
             {
                test: /\.scss$/,
                use: ExtractTextWebpackPlugin.extract({
                    use: [
                        {loader: 'css-loader'},
                        {loader: 'sass-loader'},
                    ],
                }),
            },
        ],
    },
    plugins: [
        new ExtractTextWebpackPlugin({
            allChunks: true,
            filename: '[name]/[name].[hash:8].css',
        }),
    ],
}

: 上面的例子对 .scss 文件进行了转译,并且在在输出的 css 文件后加了 hash 值(每次修改 css 都会变,避免缓存)。编译后的 css 文件会以 <link/> 的形式插入 html

3.5 本地 server 开发 && 热更新

使用 webpack-dev-server 可以在本地启动 node server 并启一个端口,同时其默认开启热更新以便在开发过程中实时观看代码修改的效果

  1. 下载 webpack-dev-server
npm i -D webpack-dev-server
  1. 配置 webpack.config.js
module.exports = {
    devServer: {
        index: 'index/index.html',  // 入口文件
        contentBase: [path.join(__dirname, 'dist')],  // 打包后的资源目录
        compress: true,
        port: 9000 // 端口
    }
}
  1. 在 package.json 配置 npm 命令, 并启动
{
  "scripts": {
      "start": "webpack-dev-server"
  },
}

注: webpack-dev-server 还支持函数式的使用方式,以在运行过程中提供更灵活的配置。详情见文档

5 性能优化

待续。。。

6 编写自己的 loader

待续。。。

接下来会将会深入介绍 webpack 的原理、我在实际工作中遇到的问题与性能优化、并亲手写一个属于自己的 loader。这些文章应该会单独启一篇,到时候会将链接贴在这。喜欢的小伙伴可以比心并持续关注哦