「Webpack」初学 webpack 配置(上)

175 阅读4分钟

源代码链接:
github.com/huyiling111…

目标一:用 webpack 编译 JS


首先下载 webpack

进入官网=>DOCUMENTATION=>GUIDES=>getting started=>Basic Setup=>并创建 src 下的 index.js

npm init -y
yarn add webpack-cli --dev


注意:可能没有下载到 webpack,只需要查看 package.json 有没有对应的版本号。

然后由于是本地安装,所以需要指定在哪里去找 webpack 的执行程序

 ./node_modules/.bin/webpack --version


image.png
还有一种简易的方法,就是

npx webpack


npx 会自动帮我们找 webpack 在本地的哪个地方

当我们运行之后,
image.png
会发现多了一个 dist 文件,里面还有 main.js 这就是转译 index.js 的结果

转译 JS 初体验
在 index.js 里写一些浏览器里不能直接用的 ES6 语法, 再用 webpack 转译,看能否使用

// index.js
import x from "./1.js";
console.log(x);

// 1.js
export default "xxxxx";


转译后的 main.js:
image.png
也就是说 webpack 敏锐地发现了其实我们的目标就是要打印'xxxxx'这个字符串

加上 webpack 的配置文件
webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].[contenthash].js",
  },
};

目标二:理解文件名中 hash 的用途


小知识点:HTTP 响应头里的 Cache-Control:public max-age=某某

所以文件名中 hash 的用途就是便于增加缓存,如果内容不更新就一直缓存,如果更新,就用新的文件名重新发送请求,加一个哈希值就相当于给文件加了一个版本号缓存的意义在于浏览器知道哪些变了哪些没变

同时,由于每次重新执行 webpack, 都会生成一个 js 文件,所以为了不占用过多内存,我们每次执行时,应该先删除现有的 dist 文件夹,再执行
于是要配置一下 package.json

"scripts": {
    "build": "rm -rf dist && webpack",  // 就是这一句
    "test": "echo \"Error: no test specified\" && exit 1"
  },


以后每次 yarn build , 就会执行"rm -rf dist && webpack", 即先删除,再重新编译

目标三: 用 webpack 生成 html


安装

yarn add --dev html-webpack-plugin


再 yarn build 就会自动生成一个 index.html
image.png
此时的 webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].[contenthash].js",
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "My App",
      template: "src/assets/index.html",
    }),
  ],
};


以上代码是说按照 "src/assets/index.html" 为模板,title 为 MY APP 生成一个网页

src/assets/index.html:

<!DOCTYPE html>
<html lang="ch-ZN">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
    />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    // 根据配置里的title生成 title
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

目标四: 用 webpack 引入 CSS


直接引入 CSS 报错:
image.png
说需要一个 css loader
下载即可
yarn add css-loader --dev
yarn add style-loader --dev
再修改配置文件

webpack.config.js;

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

const path = require("path");
module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].[contenthash].js",
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "My App",
      template: "src/assets/index.html",
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        //寻找所有带有.css的文件
        use: ["style-loader", "css-loader"],
        //发现任何带有.css的文件就用css-loader去处理,css-loader把内容读到js里,style-loader的作用是把css-loader读到的内容变成style标签
      },
    ],
  },
};


然后再 yarn build
然后如果引入 css, webpack 就会把 css 标签读出来放到 style 标签
可以通过命令行 cd dist 然后 http-server . -c-1 预览
image.png
红色圈中的就是加载的 css
现在我们把 css 放进了 style 标签
但如果我们希望单独抽成 css 文件呢?
下载插件:

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


添加配置:
webpack.js.org/plugins/min…

添加配置:

webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
module.exports = {
    mode: "production",
    devServer: {
        contentBase: './dist',
    },
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    },
    plugins: [new HtmlWebpackPlugin(
        {
            title: 'My App',
            template: "src/assets/index.html"
        }
    ), new MiniCssExtractPlugin({
        filename: '[name].[contenthash].css',
        chunkFilename: '[id].[contenthash].css',
        ignoreOrder: false,
    })],
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {

                            publicPath: '../',
                        },
                    },
                    'css-loader',
                ],

            }
        ]
    }
}

目标五:简化编译


每次修改 css, 首先是在 dist 文件夹里 http-server -c-1 开启服务器,如果要修改,就要断掉服务器,然后再改 css, 再重新 yarn build, 太麻烦了。
所以我们想要简化这一过程,需要用到 webpack-dev-server
首先安装
yarn add webpack-dev-server --dev
配置方法:
webpack.js.org/guides/deve…

然后每次启动从 yarn build, 改成 yarn start
这样每次运行后,就会自动打开浏览器

配置方法

package.json
"scripts": {
    "build": "rm -rf dist &&  webpack",
    "start": "webpack-dev-server --open",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
webpack.config.js
//此处省略

module.exports = {
    mode: "development",
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist',
    },
    entry: './src/index.js',
    // 此处省略


注意点:并不改变 dist 文件

目标六:根据模式选择不同的编译


目标:配置两种模式需求

  • development 开发模式
    1. 执行命令 yarn start 和配置默认文件 webpack.config.js
    2. 把 css 生成为 style 标签, webpack-dev-server 运行在本地服务器模拟
  • production 生产模式
    1. 执行命令 yarn build 和配置文件 webpack.config.prod.js
    2. 生成 dist 文件和把 css 单独抽成文件,丢给服务器
package.json

"scripts": {
    // 这里指定webpack.config.prod.js的路径,参数是--config
    "build": "rm -rf dist && webpack --config webpack.config.prod.js",
    "start": "webpack-dev-server --open",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
webpack.config.js
 module: {
        rules: [
            {
                test: /\.css$/i,
                // 下面这行表示生成style标签
                use: ['style-loader', 'css-loader']
            },
          }
webpack.config.prod.js

module: {
        rules: [
            {
                test: /\.css$/i,
                 // 下面这行表示生成css文件
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            },

目标七:基于两种配置文件的优化代码


但是问题是,这两个文件只有少数几行不一样,其他都完全一样,有没有更好的办法?
有!使用 JS 的继承思想
首先我们准备一个 webpack.config.base.js 把所有的公共属性都放进去

const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
module.exports = {
  devServer: {
    contentBase: "./dist",
  },
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].[contenthash].js",
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "My App",
      template: "src/assets/index.html",
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
      },
    ],
  },
};


然后 webpack.config.js 和 webpack.config.prod.js 分别继承这个 base.js
首先引入,然后用...base 即可引入 Base 的所有属性
有一个点需要注意:
如果是不希望全部覆盖掉 base 里的东西,而是希望继承一部分,修改一部分,可以在属性内部...base.module.rules

module: {
  rules: [
    // 先继承需要的
    ...base.module.rules,
    // 再叠加我自己的, 这样就不会用我自己的这个配置覆盖掉之前的所有配置
    {
      test: /\.js$/i,
      enforce: "pre",
      use: ["source-map-loader"],
    },
  ];
}


最终修改好的配置文件分别是:

webpack.config.js;

const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
// 引入Base
const base = require("./webpack.config.base");

module.exports = {
  ...base, // 把所有的base里的配置都加载进来
  mode: "development",
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};
webpack.config.prod.js;

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 引入Base
const base = require("./webpack.config.base");

module.exports = {
  ...base,
  mode: "production",
  plugins: [
    // 先继承需要的
    ...base.plugins,
    // 再叠加我自己的, 这样就不会用我自己的这个配置覆盖掉之前的所有配置
    new MiniCssExtractPlugin({
      filename: "[name].[contenthash].css",
      chunkFilename: "[id].[contenthash].css",
    }),
  ],

  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: "../",
            },
          },
          "css-loader",
        ],
      },
    ],
  },
};

总结

  1. webpack 功能:转译代码、构建 build、代码压缩、代码分析。
  2. webpack-dev-server 的作用包括文件内容变化就自动转译代码。
    并自动刷新页面提供 server 方便开发预览。
  3. webpack 将 CSS 文件引入到 JS 中,并转为 style 标签插入到 head 标签里,需要用到 style-loader 和 css-loader
  4. webpack 将 CSS 代码提取成单独的文件,需要用到 MiniCssExtractPlugin
  5. webpack 中的 loader 和 plugin 区别?在下一部分解释