手把手搭建一个webpack配置项目

配置的功能包括

1.ES6/REACT/CSS/LESS/IMG解析
2.文件监听和热更新
3.HTML/CSS文件生成、代码压缩、资源清理
4.文件指纹

1.创建一个项目,安装webpack

前提:node环境,创建项目test-project,初始化package.json和webpack

desktop % mkdir test-project
test-project % cd test-project && npm init -y
test-project % npm i webpack webpack-cli -D

安装成功后看下webpack版本,目前笔者这边是4.44.1

test-project % ./node_modules/.bin/webpack --version
4.44.1

通过vscode打开项目,根目录下创建webpack.config.js、src/index.js、src/helloworld.js
webpack.config.js

"use strict";

const path = require("path");

module.exports = {
  // 提供打包文件的入口
  entry: "./src/index.js",
  // 提供打包输出的目录
  output: {
    path: path.join(__dirname, "dist"), // 输出文件夹
    filename: "boundle.js", // 输出文件名
  },
  // 提供打包环境:production、development、none
  mode: "production",
  // 提供loader插件用于解析JSX/ES6/CSS/LESS/IMG等(由于webpack只能识别JSON和JS文件)
  module: {
    rules: [],
  },
  // 提供一些插件配置,用于解析外的处理(打包、压缩、文件生成等)
  plugins: [],
};

index.js

import { helloworld } from "./helloworld";
helloworld();

src/helloworld.js

export function helloworld() {
  document.write("Hello world!");
}

配置package.js的webpack打包命令执行npm run build

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
},

得到dist文件以及其内容

image.png

在dist创建index.html,引入打包后的js文件,浏览器打开页面上正常显示:Hello world!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello World!</title>
</head>
<body>
    <script type="text/javascript" src="boundle.js"></script>
</body>
</html>
2.ES6/REACT/CSS/LESS/IMG解析

loader插件:
ES6:babel-loader、@babel/core、@babel/preset-env
REACT:react、react-dom、@babel/preset-react
CSS/LESS:style-loader、css-loader、less-loader
IMG:file-loader
安装插件

test-project % npm i babel-loader @babel/core @babel/preset-env react react-dom @babel/preset-react style-loader css-loader less-loader file-loader -D

babel的使用需要.babelrc文件的配置

{
    "presets": [
        "@babel/preset-env", // 支持解析ES6
        "@babel/preset-react" // 支持解析REACT
    ]
}

修改webpack.config.js文件中的loader配置,rules为一个数组,每个对象是一个loader配置,test是一个校验,匹配支持该校验的文件,use指的使用何种loader,多个时使用数组(由于webpack的解析是一个自下向上的树解析过程,所以配置多个loader时,最上解析的loader放最前面)

module: {
  rules: [
    {
      test: /.js$/,
      use: "babel-loader",
    },
    {
      test: /.css$/,
      use: ["style-loader", "css-loader"],
    },
    {
      test: /.less$/,
      use: ["style-loader", "css-loader", "less-loader"],
    },
    {
      test: /.(png|jpg|jpeg|gif)$/,
      use: "file-loader",
    },
  ],
},

创建src/test.js、src/test.css、src/test.less文件
test.js

import React from "react";
import ReactDOM from "react-dom";
import Img from "./images/test.jpg";
import "./test.css";
import "./test.less";

class Test extends React.Component {
  render() {
    return (
      <div className="test-box">
        <span>hello react!</span>
        <img src={Img} />
      </div>
    );
  }
}

ReactDOM.render(<Test />, document.getElementById("root"));

test.css

.test-box {
    font-size: 20px;
    color    : #00f
}

test.less

.test-box {
    img {
        width : 300px;
        height: auto;
    }
}

由于本次查看的是test.js,我们需要重新调整webpack入口配置,entry可配置多个,使用对象包裹,output调整输出的名字,使用占位符“[name]”

// 提供打包文件的入口
entry: {
  index: "./src/index.js",
  test: "./src/test.js",
},
// 提供打包输出的目录
output: {
  path: path.join(__dirname, "dist"), // 输出文件夹
  filename: "[name].js", // 输出文件名
},

执行打包命令npm run build,添加dist/test.html,浏览器查看正常显示样式和图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello World!</title>
</head>
<body>
    <!-- 添加react挂载根节点 -->
    <div id="root"></div>
    <script type="text/javascript" src="test.js"></script>
</body>
</html>
3.文件监听和热更新

在开发环境下,由于每次修改文件我们都需要打包查看,webpack提供了文件监听和热更新的功能
文件监听:配置package.json命令"watch": "webpack --watch" ,使用npm run watch,这时候webpack会将我们修改的文件缓存在磁盘,当文件进行修改每隔一段时间(300ms)会进行匹配替换,此时我们仍需要刷新浏览器才可以看到最新代码
热更新:需要添加plugins插件HMR(HotModuleReplacementPlugin),安装webpack-dev-server,配置package.json命令"dev": "webpack-dev-server --open"

test-project % npm i  webpack-dev-server -D
// 提供打包环境:production、development、none
mode: "development",
// 提供一些插件配置,用于解析外的处理(打包、压缩、文件生成等)
plugins: [
  // 代码热更新插件
  new HotModuleReplacementPlugin(),
],
devServer: {
  contentBase: "./dist",
  hot: true,
},

注:清除dist目录重新打包,创建index.html引用test.js,执行npm run dev,当我们修改test.js后浏览器会自动刷新更新为最新的代码
当我们使用热更新启动时,打包后的boundle文件在浏览器中是运行在localhost:8080服务端的,会与客户端浏览器建立websocket长连接,当文件发生改动,服务端会主动推送消息给浏览器,浏览器接收到后进行一个reload


image.png

image.png
4.HTML/CSS文件生成、代码压缩、资源清理

plugins插件:
HTML文件生成、代码压缩:html-webpack-plugin
CSS文件生成、代码压缩:mini-css-extract-plugin、optimize-css-assets-webpack-plugin、cssnano
资源清理:clean-webpack-plugin
安装插件

test-project % npm i html-webpack-plugin -D
test-project % npm i mini-css-extract-plugin -D
test-project % npm i optimize-css-assets-webpack-plugin cssnano -D
test-project % npm i clean-webpack-plugin -D

修改webpack配置

plugins: [
  // 生成css文件插件
  new MinCssExtractPlugin({
    filename: "[name].css",
  }),
  // css文件代码压缩插件
  new OptimizeCssAssetsPlugin({
    assetNameRegExp: /\.css$/g,
    cssProcessor: require("cssnano"),
  }),
  // html文件生成、代码压缩插件
  new HtmlWebpackPlugin({
    template: path.join(__dirname, "src/index.html"),
    filename: "index.html",
    chunks: ["index"],
    inject: true,
    minify: {
      html5: true,
      removeComments: false,
      collapseWhitespace: true,
      preserveLineBreaks: false,
      minifyJS: true,
      minifyCSS: true,
    },
  }),
  new HtmlWebpackPlugin({
    template: path.join(__dirname, "src/test.html"),
    filename: "test.html",
    chunks: ["test"],
    inject: true,
    minify: {
      html5: true,
      removeComments: false,
      collapseWhitespace: true,
      preserveLineBreaks: false,
      minifyJS: true,
      minifyCSS: true,
    },
  }),
  // 清理打包后的目录插件
  new CleanWebpackPlugin(),
],

由于style-loader是将生成的样式插入到页面的header中,和MinCssExtractPlugin会有冲突,所以调整rules

rules: [
  {
    test: /.css$/,
    use: [MinCssExtractPlugin.loader, "css-loader"],
  },
  {
    test: /.less$/,
    use: [MinCssExtractPlugin.loader, "css-loader", "less-loader"],
  },
],

创建src/index.html、src/test.html,执行npm run build查看

image.png

代码都进行了压缩,且生成了html和css文件,浏览器查看显示正常

5.文件指纹

由于浏览器对一些静态文件会做缓存,当文件发生更改我们编译后虽然内容发生了变化,但名字没变化导致浏览器没检测到,所以引入了文件指纹,给生成的文件名后添加hash值
js:chunkhash
css:contenthash
img:hash
配置webpack文件(:8表示取hash值的前8位数)

output: {
  path: path.join(__dirname, "dist"),
  filename: "[name]_[chunkhash:8].js",
},
module: {
  rules: [
    {
      test: /.(png|jpg|jpeg|gif)$/,
      use: [
        {
          loader: "file-loader",
          options: {
            name: "[name]_[hash:8].[ext]",
          },
        },
      ],
    },
  ],
},
plugins: [
  // 生成css文件插件
  new MinCssExtractPlugin({
    filename: "[name]_[contenthash:8].css",
  }),
]

再次执行npm run build,浏览器查看显示正常


image.png
尾语

至此,支持基本开发打包的项目配置就完成啦😄😄😄

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容