webpack 4 学习随记 二 webpack核心概念

428 阅读5分钟

前言

webpack第二篇, webpack的四个核心概念;

相关链接: webapck

  • 入口(Entry):指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始

  • 输出(Output):在哪里输出它所创建的 bundles

  • 模块(Module):在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。

  • 代码块(Chunk):,一个 Chunk 由多个模块组合而成,用于代码合并与分割

  • 模块转换器(Loader):让 webpack 能够去处理那些非 JavaScript 文件

  • 插件(Plugins):用于执行范围更广的任务

Entry

可以通过在 webpack 配置中配置 Entry 属性,来指定一个入口起点(或多个入口起点)。默认值为 ./src。

配置 Entry 属性

单个入口(简写)语法 (用法:entry: string|Array)

webpack.config.js

  • Entry 属性的单入口语法:
module.exports = {
  entry: {
    main: './src/index.js'
  }
};
  • 以下是单入口文件简写:
module.exports = {
  entry: {
    main: './src/index.js'
  }
};
  • 如果想将多个相关的文件配置在一起, 那还可以将文件路径按照数组配置,它会将它们的依赖关系绘制到一个块里(这里解释我是按照官方文档来写的,这里也只是简单的做了配置,没有深入研究,也就按照官方来吧!)
module.exports = {
  entry: [ 
    './src/index.js',
    './src/index_1.js'
  ],
  output: {
    filename: 'bundle.js'
  }
};

*如果是想用webpack快速配置时, 单入口文件是最好的选择;

对象语法 ( 用法:Entry: {[entryChunkName: string]: string|Array} )

  • 对象语法是定义入口的可扩展的方法,可复用,也能与其他部分组合配置组合使用,是目前比较的流行的用法,可按照不同环境,构建的目标和运行时进行分离,然后使用webpack-merge类工具将其合并;

以下是对象语法配置及其实际用例:

webpack.config.js

module.exports = {
  entry: {
    main: './src/index.js',
    main_1: './src/index_1.js'
  }
};

Output

在 webpack配置 Output 属性是一个对象,包括以下两点:

  • filename 用于输出文件的文件名。

  • 目标输出目录 path 的绝对路径。

  • Entry 属性的单入口 Output 配置如下: webpack.config.js

module.exports = {
  output: {
    filename: 'bundle.js',
  }
};
  • Entry 属性的多入口 Output 配置如下: webpack.config.js
module.exports = {
  entry: {
    main: './src/index.js',
    app: './src/index.js'
  },
  output: {
    filename: '[name].js',   // 使用占位符
    path: __dirname + '/dist'
  }
};
  • 打包html的js引用带上 cdn域名, 配置如下:

webpack.config.js

module.exports = {
  //...
  output: {
    publicPath: 'https://cdn.com.cn',   // 使用publicPath 这个配置项
    filename: '[name].js',   // 使用占位符
    path: __dirname + '/dist'
  }
};

在编译时不知道 publicPath 情况下,publicPath 是可以置空;并在运行时通过入口点文件中的__webpack_public_path__变量进行动态设置

Loader

什么是Loader

webpack仅能理解JavaScript和JSON文件, 那这里 webpack 就需要用到 Loader 来预处理文件。使我们能打包除 JavaScript 之外的任何静态资源,Loader 对模块的源代码进行转换,可以使你在 import 或"加载"模块时预处理文件,具体的相关文档 loader

简单来说 Loader 是一个转换器,用于对源代码进行转换,输出新的结果;

以图片文件为例: 如果我想要加载图片 .jepg 的文件, 或者将 TypeScript 转为 JavaScript。为此,首先安装相对应的 loader:

安装 loader工具;

 npm install -D file-loader 
 npm install --save-dev ts-loader

然后在 webpack 对每个 .jepg 使用 file-loader,对所有 .ts 文件使用 ts-loader:

  module: {
    rules: [
      {
        test: /\.jpeg$/,
        use: {
          loader: 'file-loader'
        }
      },
      {
        test: /\ts/,
        use: 'ts-loader'
      }
    ]
  }

运行

 npm run build

图片打包配置完成之后在dist目录下可以看的有一个图片文件;

使用 Loader

应用程序中有三种使用 Loader 方法:

  • 配置(推荐):在 webpack.config.js 文件中指定 Loader。
  • 内联:在每个 import 语句中显式指定 loader。
  • CLI:在 shell 命令中指定它们。

配置[Configuration]

module.rules 允许在 webpack 配置中指定多个 Loader。 这是展示 Loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 Loader 有个全局概览:

module: {
    rules: [
      {
        test: /\.jpeg$/,
        use: {
          loader: 'file-loader'
        }
      },
      {
        test: /\ts/,
        use: 'ts-loader'
      }
    ]
  }

内联

可以在 import 语句或任何等效于 "import" 的方式中指定 Loader。使用 ! 将资源中的 Loader 分开。分开的每个部分都相对于当前目录解析。

通过前置所有规则及使用 !,可以对应覆盖到配置中的任意 Loader。

选项可以传递查询参数,例如 ?key=value&foo=bar,或者一个 JSON 对象,例如 ?{"key":"value","foo":"bar"}。

尽可能使用 module.rules,因为这样可以减少源码中的代码量,
这样在出错时更快地调试和定位 loader 中的问题。

CLI

通过 CLI 使用 Loader:

这样会对 .ts 文件使用 ts-loader,对 .css 文件使用 style-loader 和 css-loader。

  • 不同的 Loader 可以打包不同的静态资源
  • 以下是整理的一些我配置webpack 经常会使用到的loader
类型Loader作用
文件url-loader像 file loader 一样工作,但如果文件小于限制,可以返回 data URL
文件file-loader将文件发送到输出文件夹,并返回(相对)URL
转换编译(Transpiling)babel-loader使用Babel加载ES2015 +代码并转换为ES5
转换编译(Transpiling)ts-loader像JavaScript一样加载TypeScript 2.0+
模板(Templating)html-loader导出 HTML 为字符串,需要引用静态资源
样式style-loader将模块的导出作为样式添加到 DOM 中
样式css-loader解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
样式less-loader加载和转译 LESS 文件中
样式sass-loader加载和转译 SASS/SCSS 文件
样式postcss-loader使用 PostCSS 加载和转译 CSS/SSS 文件
样式eslint-loader使用ESLint整理代码的PreLoader
框架(Frameworks)vue-loader加载 Vue 组件
框架(Frameworks)eslint-loader使用ESLint整理代码的PreLoader

Loader 打包静态资源(图片)

  • 设置图片文件名
module: {
    rules: [
      {
        test: /\.jpeg$/,
        use: {
          loader: 'file-loader',
          options: {
            // placeholder  占位符
            name: '[name].[ext]' // 打包源文件的名称和后缀
            // name: '[name]_[hash].[ext]' // 打包加上 hash 值的文件名称
          }
        }
      }
    ]
  },

Plugins

我们看一下官网的定义,webpack 插件由以下部分组成:

  1. webpack 插件是一个具有 apply 属性的 JavaScript 对象。

  2. apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。

  3. 插件目的在于解决 loader 无法实现的其他事

ConsoleLogOnBuildWebpackPlugin.js

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

class ConsoleLogOnBuildWebpackPlugin {
    apply(compiler) {
        compiler.hooks.run.tap(pluginName, compilation => {
            console.log("webpack 构建过程开始!");
        });
    }
}

compiler hook 的 tap 方法的第一个参数,应该是驼峰式命名的插件名称。建议为此使用一个常量,以便它可以在所有 hook 中复用。 具体参考官方文档;

配置

由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。 根据你的 webpack 用法,这里有多种方式使用插件

安装 Plugins 插件;

 npm install  --save-dev html-webpack-plugin 
 npm install --save-dev uglifyjs-webpack-plugin

webpack.config.js

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

module.exports = {
  mode: 'none',  
  entry: './index.js',
  module: {
    rules: [
      {
        test: /\.(jpeg|png|svg|gif|jpg)$/,
        use: {
          loader: 'url-loader',    
          options: {
            limit: 20480   
          }
        }
      },
      {
        test: /\.(eot|woff|ttf)$/,
        use: {
          loader: 'file-loader'  
        }
      },
      {
        test: /\.(scss)$/,
        use: [  
          'style-loader', 
          {
            loader: 'css-loader', 
            options: {
              importLoaders: 2
            }
          },
          'sass-loader',
          'postcss-loader'
        ],
      }
    ]
  },
  plugins: [
    new uglifyJsPlugin(), //压缩js文件
    new HtmlWebpackPlugin({  
      minify: {  // 是对html文件进行压缩,removeAttrubuteQuotes 是却掉属性的双引号。
        removeAttributeQuotes: true
      },
      hash: true, // 为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。
      template: path.resolve(__dirname, './index.html'),  //是要打包的html模版路径和文件名称。
      filename: 'index.html'
    }),
  ],
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}

执行命令后 在 dist 目录下有一个 index.html 和 bundle.js;同时 index.html 已经自动引入了 bundle.js, 查看 bundle.js 文件看到代码也是压缩的 js 文件

参考资料

webpack.js.org

www.webpackjs.com

后语

前路漫漫 ~~