这篇文章主要就是一步一步地,实现用webpack配置一个简单的web开发环境。

初始化文件夹,新建配置文件和测试代码

新建一个空的文件夹,这里就叫做webpack-basic-project,然后在文件夹下面执行

npm init -y

安装webpack依赖

yarn add --dev webpack webpack-cli webpack-dev-server 

新建一个webpack的配置文件webpack.config.js
新建一个babel配置文件.babelrc
新建src文件夹,并添加index.js,index.html,index.scss,加入测试代码
index.js:

import "./index.scss";

function test() {
  var root = document.getElementsByClassName("root")[0];
  var p = document.createElement("p");
  var text = document.createTextNode("hello world");
  p.appendChild(text);
  root.appendChild(p);
}

test();

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>webpack basic sample</title>
  </head>
  <body>
    <div class="root"></div>
  </body>
</html>

index.scss

.root {
  color: red;
}

也就是这个时候我们的文件夹结构是:
image.png

配置单页应用

一个最基本的配置是这样的

module.exports = {
    entry: {},
    mode: "",
    output: {},
    module: {
        rules: [
        ]
    },
    plugins: [] 
}
mode

由于webpack4在production模式下会启动js压缩,为了方便看效果,我们先用开发模式吧

 mode: "development"
entry

我们先添加entry,也就是入口文件

 entry: {
    index: "./src/index.js"
 },
output

然后添加output,也就是编译后输出的文件夹,我们最后通过浏览器访问的也就是这里的。

  output: {
    path: path.join(__dirname, "dist"),
    // publicPath: "./" 会给引入的文件前面加个前缀,主要是用于生产环境
    filename: "[name].js"
  },
loader

接着配置Loader,loader就是用来解析文件的。我们需要解析的就是js,css,图片、字体文件。一个一个说明。

解析js: 用babel-loader

安装依赖:

  • @babel/core是babel的核心api包,必须要安装。
  • @babel/preset-env 它提供一个target参数,可以让我们设置要支持的目标环境,从而能用不同的解析方式去转换js。官方推荐通过新建一个.browserslistrc来设置。
  • @babel/preset-react 考虑到后面要用react加进去的。不需要的可以不添加。
yarn add --dev @babel/core @babel/preset-env babel-loader @babel/preset-react

在webpack.config.js里添加babel-loader

  module: {
    rules: [
      {
        test: /\.(js|mjs|jsx|ts|tsx)$/,
        use: "babel-loader"
      }
    ]
 }

编辑.babelrc

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": []
}
解析scss

安装依赖

  • sass-loader:转换sass为css
  • css-loader: 解析css
  • mini-css-extract-plugin: 把css提取成一个独立的文件
yarn add --dev sass-loader node-sass css-loader mini-css-extract-plugin

由于loader是链式调用,从右到左,也就是最右边的loader执行完的结果会传递给它旁边的Loader。所以我们写的顺序是sass-loader->css-loader->mini-css-extract-plugin

  const MiniCssExtractPlugin = require("mini-css-extract-plugin");
  module.exports = {
    module: {
        rules: [
              {
                test: /.scss$/,
                use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
              }
        ]
    }
  }
解析图片跟字体

安装依赖

yarn add --dev file-loader

添加配置

module: {
  rules: [
      {
        test: /.(png|jpg|gif|jpeg)$/,
        use: [
          {
            loader: "file-loader"
          }
        ]
      },
      {
        test: /.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: "file-loader"
          }
        ]
      }
  ]
}  
plugins

安装依赖

yarn add --dev html-webpack-plugin clean-webpack-plugin
  • html-webpack-plugin:用于根据html模板,生成一个新的html文件,把我们打包出来的js文件嵌入到html中
  • clean-webpack-plugin:用于每次打包前都把dist文件夹清空。
  • mini-css-extract-plugin:在loader那里已经安装过了,用于把打包出来的css文件提取到一个独立的文件,而不是嵌入在style标签里。
 plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, `./src/index.html`),
      filename: "index.html",
      chunks: ["index"],
      inject: true
    }),
    new MiniCssExtractPlugin({
      filename: "[name].css"
    }),
    new CleanWebpackPlugin()
 ],
devServer

由于我们开发模式下使用webpack-dev-server,所以这里设置一下热替换

module.exports = {
  devServer: {
    hot: true
  }   
}

最后,在package.json下面添加启动命令

"scripts": {
    "build": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server --config webpack.config.js --open"
  },

这个时候,我们执行npm run build,就会发现在dist文件夹下面已经有输出了。打开index.html,可以看到它引入了index.js跟index.css,打开也确实是输出了hello world。
image.png
执行npm run dev,打开http://localhost:8080,也可以看到index.html的内容。由于webpack-dev-server的输出是在内存中的,所以我们这个时候是不会创建dist文件夹的。

改成多页应用

准备测试代码

那就在src下新建一个文件夹,就叫search/search.js.由于我们准备让search.js跟index.js功能差不多,干脆直接新建一个common.js来写这个函数,然后search.js跟index.js去调用它。
common/common.js

function test(type) {
  var root = document.getElementsByClassName("root")[0];
  var p = document.createElement("p");
  var text = document.createTextNode(`${type} world`);
  p.appendChild(text);
  root.appendChild(p);
}

export default test;

search/search.js

import test from "../common/common.js";
test("search");

index.js

import "./index.scss";
import test from "./common/common.js";
test("hello");

这时的文件夹结构是:
image.png

修改webpack配置

这里主要修改两个地方,添加一个入口entry来打包search.js,同时也添加一个新的html页面去引用search.js.

  entry: {
    index: "./src/index.js",
    search: "./src/search/search.js"
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, `./src/index.html`),//引入html模板
      filename: "index.html", // 打包出来的html模板名称
      chunks: ["index"], // 这里的chunks就是对应上面entry打包出来的js文件
      inject: true
    }),
    new HtmlWebpackPlugin({
      template: path.join(__dirname, `./src/index.html`),
      filename: "search.html",
      chunks: ["search"],
      inject: true
    }),
  ]

这时候我们再执行npm run build就可以发现dist下面已经打包出两套页面文件,可以直接打开index.html跟search.html看打包后的结果。执行npm run dev,访问http://localhost:8080/search.html跟http://localhost:8080/index.html也可以看到我们这两个文件的执行结果。

提取公共部分

common.js其实在两个文件都被用到了,这个时候,我们会希望把它打包成一个独立的文件。
添加配置:

module.exports = {
  optimization: {
    splitChunks: {
      minSize: 0,
      cacheGroups: {
        common: {
          name: "commons",
          chunks: "all",
          minChunks: 2, // 引用大于两次就独立打包出来
          priority: 10
        }
      }
    }
  },
}

这个时候在html的chunks也要引入common.js,才能让页面正常工作。

  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, `./src/index.html`),
      filename: "index.html",
      chunks: ["index", "commons"], // 加入common.js
      inject: true
    }),
    new HtmlWebpackPlugin({
      template: path.join(__dirname, `./src/index.html`),
      filename: "search.html",
      chunks: ["search", "commons"],
      inject: true
    })
 }

执行npm run build,可以看到common.js已经被独立打包出来了。并且在html里面也有引入common.js。
image.png


supportlss
230 声望16 粉丝