前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WebPack 模块化打包工具(下)

WebPack 模块化打包工具(下)

作者头像
Nian糕
修改2024-03-16 16:06:50
1.2K0
修改2024-03-16 16:06:50
举报

本篇博文的内容根据 入门 Webpack,看这篇就够了 该篇文章总结而来,其代码、模块示例、功能拓展部分均有所删减,若是想了解更多关于 WebPack 的详细内容,敬请参考原文

WebPack 模块化打包工具(上) 这篇文章当中,我们已经能成功使用 webpack 打包了文件,并配置了devtooldevserver选项,在这篇文章当中,我们将介绍更多关于 webpack 的用法

Loaders

通过使用不同的 Loaders,webpack 有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如说分析转换scsscss,或者把 ES6 或ts文件转换为现代浏览器兼容的js文件,对 React 的开发而言,合适的 Loaders 可以把 React 的中用到的jsx文件转换为js文件

Loaders 需要单独安装并且需要在webpack.config.js 中的modules关键字下进行配置,Loaders 的配置包括以下几方面:

  • test:一个用以匹配 loaders 所处理文件的拓展名的正则表达式(必须)
  • loader:loader的名称(必须)
  • include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选)
  • query:为 loaders 提供额外的设置选项(可选)

我们通过安装和配置 Babel 依赖包来进一步了解 Loaders 吧,我们需要安装拥有核心功能的babel-core包,解析 ES6 的babel-env-preset包和解析 JSX 的babel-preset-react包,键入以下命令一次完成安装

// npm一次性安装多个依赖模块,模块之间用空格隔开
npm i babel-core babel-loader babel-preset-env babel-preset-react -D

安装完成之后,我们需要在 webpack 文件中配置 Babel

// webpack.config.js
module.exports = {
    devtool: 'eval-source-map',
    entry:  __dirname + "/app/main.js", 
    output: {
        path: __dirname + "/public",
        filename: "bundle.js"
    },
    devServer: {
        contentBase: "./public", //本地服务器所加载的页面所在的目录
        historyApiFallback: true, //不跳转
        inline: true //实时刷新
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: [
                            "env", "react"
                        ]
                    }
                },
                exclude: /node_modules/
            }
        ]
    }
}

现在 webpack 的配置已经允许我们使用 ES6 以及 JSX 的语法了,我们也是使用之前的例子进行测试,不过这次我们会使用到 React,所以还需要安装一下 React 的依赖包,并在app文件夹下新建config.json的文件

npm i react react-dom -D
{
    "greetText": "Love and Peace from JSON!"
}
//Greeter.js
import React, {Component} from 'react'
import config from './config.json';

class Greeter extends Component{
    render() {
        return (
            <div>
                {config.greetText}
            </div>
        );
    }
}

export default Greeter
// main.js
import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

render(<Greeter />, document.getElementById('root'));

运行npm satart命令进行编译打包,再运行npm run server命令启动本地服务器

运行结果
运行结果

虽然我们当前项目中 Babel 的配置选项很少,完全可以写在webpack.config.js文件当中,当实际项目中,我们是会对 Babel 进行各种各样的配置的,这时候就不适合继续写在webpack.config.js文件中了,所以我们将 Babel 的配置独立到一个.babelrc文件中,webpack 会自动读取.babelrc文件里的 Babel 配置选项

// webpack.config.js
module.exports = {
    devtool: 'eval-source-map',
    entry:  __dirname + "/app/main.js", 
    output: {
        path: __dirname + "/public",
        filename: "bundle.js"
    },
    devServer: {
        contentBase: "./public", //本地服务器所加载的页面所在的目录
        historyApiFallback: true, //不跳转
        inline: true //实时刷新
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            }
        ]
    }
}
// .babelrc
{
    "presets": ["env", "react"]
}

CSS Modules

JavaScript 模块化处理相信大家已经很熟悉了,而 CSS 同样也能进行模块化处理,webpack 提供的css-loaderstyle-loader可以对样式表进行处理,css-loader使你能够使用类似@importurl(...)的方法实现require()的功能,style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入 webpack 打包后的 JS 文件中

npm i style-loader css-loader -D
// webpack.config.js
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    },
                    {
                        loader: "css-loader"
                    }
                ]
            }
        ]
    }
};

注意这里对同一个文件引入多个 loader 的方法

随后,我们在app文件夹里创建一个名字为main.css的文件,并设置如下样式

/* main.css */
html {
  box-sizing: border-box;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  margin: 0;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

h1, h2, h3, h4, h5, h6, p, ul {
  margin: 0;
  padding: 0;
}

#root {
  color: blue;
}

我们项目中用到的 webpack 只有单一的入口,其它的模块需要通过import, require, url等方式与入口文件建立其关联,为了让 webpack 能找到main.css文件,我们需要把它导入main.js

// main.js
import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';
import './main.css'; //使用require导入css文件

render(<Greeter />, document.getElementById('root'));
运行结果
运行结果

Webpack 对 CSS 模块化提供了非常好的支持,只需要在 CSS loader中进行简单配置即可,然后就可以直接把 CSS 的类名传递到组件的代码中,这样做有效避免了全局污染

// webpack.config.js
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    },
                    {
                        loader: "css-loader",
                        options: {
                            modules: true, // 指定启用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                        }
                    }
                ]
            }
        ]
    }
};

我们在app文件夹下创建一个Greeter.css文件来进行一下测试

/* Greeter.css */
.root {
  background-color: #eee;
  padding: 10px;
  border: 3px solid #ccc;
}

导入.rootGreeter.js

//Greeter.js
import React, {Component} from 'react'
import config from './config.json';
import styles from './Greeter.css'; //导入

class Greeter extends Component{
    render() {
        return (
            <div className={styles.root}>
                {config.greetText}
            </div>
        );
    }
}

export default Greeter
运行结果
运行结果

关于 CSS Modules 的更多用法,可以去官方文档了解更多

我们再介绍一个日常开发里经常用到的 CSS 处理器——PostCSS,首先安装postcss-loaderautoprefixer(自动添加前缀的插件)

npm i postcss-loader autoprefixer -D

同样的,也是在 webpack 配置文件中添加postcss-loader,在根目录新建postcss.config.js文件,添加如下代码之后,重新使用npm start打包时,我们写的 CSS 就会自动根据 Can i use 里的数据添加不同前缀了

// webpack.config.js
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    },
                    {
                        loader: "css-loader",
                        options: {
                            modules: true, // 指定启用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                        }
                    },
                    {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    }
}
// postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

Plugins

Plugins 是用来拓展 Webpack 功能的,它们会在整个构建过程中生效,执行相关的任务,Loaders 和 Plugins 常常被弄混,Loaders 是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,Plugins 并不直接操作单个文件,它直接对整个构建过程其作用

继续运行上面的例子,我们给项目添加几个常用的插件,HtmlWebpackPlugin这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的 JS 文件的新index.html,这在每次生成的 JS 文件名称不同时非常有用(比如添加了hash值)

npm i html-webpack-plugin -D

移除public文件夹,此插件可自动生成index.html文件,在app目录下,创建一个index.tmpl.html文件模板,这个模板包含title等必须元素,在编译过程中,插件会依据此模板生成最终的 HTML 页面,会自动添加所依赖的 CSS, JS, favicon 等文件

<!-- index.tmpl.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id='root'></div>
</body>
</html>

更新 webpack 的配置文件,并新建一个build文件夹用来存放最终的输出文件

// webpack.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    ...
    module: {
        ...
    },
    plugins: [
        new webpack.BannerPlugin('版权所有,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
        })
    ]
}
运行结果
运行结果

Hot Module Replacement(HMR)属于 webpack 插件,该插件允许你在修改组件代码后,自动刷新实时预览修改后的效果,我们需要在 webpack 中做两项配置,在 webpack 配置文件中添加 HMR 插件;在 webpack Dev Server中添加hot参数

// webpack.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    devtool: 'eval-source-map',
    entry:  __dirname + "/app/main.js", 
    output: {
        path: __dirname + "/public",
        filename: "bundle.js"
    },
    devServer: {
        contentBase: "./public", //本地服务器所加载的页面所在的目录
        historyApiFallback: true, //不跳转
        inline: true, //实时刷新
        hot: true
    },
    module: {
        ...
    },
    plugins: [
        new webpack.BannerPlugin('版权所有,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
        }),
        new webpack.HotModuleReplacementPlugin() //热加载插件
    ]
}

Babel 有一个叫做react-transform-hrm的插件,可以在不对 React 模块进行额外的配置的前提下让 HMR 正常工作

npm i babel-plugin-react-transform react-transform-hmr -D

配置 Babel

// .babelrc
{
    "presets": ["react", "env"],
    "env": {
        "development": {
            "plugins": [["react-transform", {
                "transforms": [{
                    "transform": "react-transform-hmr",
                    "imports": ["react"],
                    "locals": ["module"]
                }]
            }]]
        }
    }
}

我们再来看看其他插件,OccurenceOrderPlugin为组件分配 ID,通过这个插件 webpack 可以分析和优先考虑使用最多的模块,并为它们分配最小的 ID;UglifyJsPlugin压缩 JS 代码;ExtractTextPlugin分离 CSS 和 JS 文件

npm i extract-text-webpack-plugin -D
// webpack.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    ...
    module: {
        ...
    },
    plugins: [
        new webpack.BannerPlugin('版权所有,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
        }),
        new webpack.HotModuleReplacementPlugin(), //热加载插件
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("/app/main.css")
    ]
}
运行结果
运行结果

该章节的内容到这里就全部结束了,源码我已经发到了 GitHub WebPack_2 上了,有需要的同学可自行下载

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.01.05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Loaders
  • CSS Modules
  • Plugins
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档