webpack4配置(3)-打包css/js/图片等资源

7,156 阅读3分钟

打包css资源

使用loader

webpack可以使用各种不同loader来预处理不同格式的资源。

  1. 在项目目录下添加文件:

编写测试代码

// src/index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Page Title</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
    <div class="box"></div>
</body>
</html>
// src/css/style.css
.box{
    width:50px;
    height: 50px;
    background-color: pink;
}
  1. 安装css-loaderstyle-loader
    css-loader负责读取css文件,然后使用style-loader将css内容注入到js里面去,最终是以style标签的形式嵌入到Html代码中
    npm i -D css-loader style-loader
  2. 更改配置文件
module:
{
    test: /\.css$/,
    use: [
        {
            loader:'style-loader',  //以style标签的形式嵌入到html中
            options:{  
                insertAt:top   //嵌入位置,top指顶部,不会覆盖掉html自带的style样式
            }
        }
        'css-loader'  //解析css文件
    ]
},

module使用方法:

  • rules:一个数组,存放各种Loader
  • test:正则表达式,用来匹配不同的文件名后缀
  • loader:有多种使用方法
{
    test:/\.js$/,
    loader:'babel-loader'  //只有一个loader时
}
{
    test:/\.css$/,
    use:['style-loader','css-loader']  //多个loader,从右往左加载
}
{
    test:/\.css$/,
    use:[ 
        'style-loader',          //多个loader混合使用
        {                           //loader要设置相关参数时可以使用对象
            loader:'css-loader',
            options:{
                minimize:true
            }
        }
    ]
}

使用插件MiniCssExtractPlugin

使用css-loader+style-loader的方式是将样式打包进js文件,然后以style标签的形式嵌入页面。css样式与js文件混在一起可能导致一些样式混乱,所以使用插件将css样式统一打包进一个css文件,然后以link标签的形式嵌入页面进行资源请求。
webpack3通常使用的是ExtractWebpackPlugin,但在webpack4中已不再支持,官方推荐使用MiniCssExtractPlugin进行替代。
首先安装 :
npm i -D mini-css-extract-plugin
修改配置文件

const miniCssExtractPlugin=require('mini-css-extract-plugin');

module.exports = {
    entry: path.join(__dirname, 'src/index.js'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename:'bundle.js',
    },
    module: {
        rules:[
            {
                test: /\.css$/,
                use: [
                    {
                        loader:miniCssExtractPlugin.loader
                    },
                    'css-loader'
                ]
            }
        ]
    },
    plugins: [
        new htmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new miniCssExtractPlugin({
            filename:'[name].css'   //输出的css文件名,放置在dist目录下
        }) 
    ]
}

打开dist/index.html,可以看到以link形式引入了css样式。

自动添加前缀

我们希望可以给css自动添加浏览器前缀,可以使用插件autoprefixer.

  1. 首先安装,npm i -D postcss-loader autoprefixer
  2. postcss-loader需要一个配置文件,在根目录下新建postcss.config.js文件,写入:
module.exports={
    plugins:[require('autoprefixer')]
}
  1. 配置loader
// webpack.config.js
{
    test: /\.css$/,
    use: [
        {
            loader:miniCssExtractPlugin.loader  //抽离成一个css文件
        },
        'css-loader',    //解析css
        'postcss-loader'   //先添加前缀
    ]
}
  1. 编写css测试代码
// src/css/style.css
.box{
    width:50px;
    height: 50px;
    background-color: pink;
    transform: rotateX(30deg);
}
  1. 打包npm run build后,打开dist/main.css,可以看到tranform已经加上了webkit前缀。

压缩css/js代码

使用optimize-css-assets-webpack-plugin插件来压缩css代码。

  1. 安装 npm i -D optimize-css-assets-webpack-plugin
  2. 修改配置文件
// webpack.config.js

const opimizeCss=require('optimize-css-assets-webpack-plugin');

module.exports = {
    optimization:{   
        minimizer:[
            new opimizeCss()
        ]   
    },
    mode:'production'
    ....
}    
  1. npm run build以后打开main.css发现已经被压缩,但是在默认环境为production时自动压缩的js代码却不再压缩了,我们使用uglifyjs-webpack-plugin来压缩js代码。
  2. 安装 npm i -D uglifyjs-webpack-plugin
  3. 修改配置文件
//webpack.config.js
const uglifyJsWebpackPlugin=require('uglifyjs-webpack-plugin')

module.exports = {
    optimization:{   
        minimizer:[
            new uglifyJsWebpackPlugin({
                cache:true,  //是否缓存
                parallel:true,  //是否并发打包,同时打包多个文件
                sourceMap:true  //打包后的代码与源码的映射,方便调试
            })
            ...
        ]
        ...
}        

es6转es5

webpack里面使用了大量的es6语法,我们需要转换为es5,使用babel来完成此功能。

  1. 安装babel npm i -D babel-loader @babel/core @babel/preset-env
  2. 配置loader
{
    test:/\.js$/,
    use:[
        {
            loader:'babel-loader',
            options:{
                presets:[
                    `@babel/preset-env`  //es6转es5
                ]
            }
        }
    ]
}

打包图片资源

在js中创建图片引入

(1)引入的图片需要在入口的js文件中import进去

// index.js

import img from './img/big.jpg';  //file-loader将该图片放入到dist下,同时返回图片的地址
var imgElement = document.createElement('img');
imgElement.src = img;
document.body.appendChild(imgElement);

(2)安装file-loader并配置 npm i -D file-loader

// webpack.config.js

{
    test: /\.(png|jpg|gif|svg|jpeg)$/,
    loader: 'file-loader',
}

在css中中引入背景图片

与js引入图片用法相同,不过比起file-loader,更常用的是url-loader,可以将小图片直接base64编码,减少http请求。 (1)安装url-loader并配置 npm i -D url-loader

// webpack.config.js

{
    test: /\.(png|jpg|jpeg|gif|svg)$/,
    loader: 'url-loader',
    options: {
        limit: 1024,  //小于该值的图片会使用base64编码
        name: '[name].[hash:8].[ext]'  //打包后的图片名称 [ext]指图片格式
    }
}

直接在html写入标签

// src/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Page Title</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
    <div class="box"></div>
    <img src="./img/big.png">
</body>
</html>

打包后发现该图片的地址是写死的,并不会相对于dist,导致无法找到该图片,使用html-withimg-loader来处理html中的图片。
安装并配置 npm i -D html-withimg-loader

// webpack.config.js
{
    test:/\.html$/,
    loader:'html-withimg-loader'
}

再次打包运行后发现可以正确加载图片了。

配置不同的资源路径

现在这种配置下,所有的资源都放置在dist目录下,看起来很混乱,我们希望js在js文件夹下,css在css文件夹下,图片在img文件夹下,修改相关配置。

//webpack.config.js

module.exports = {
    entry: path.join(__dirname, 'src/index.js'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename:'js/bundle.js', //给打包输出的js添加一层目录
    },
    module: {
        rules:[
            {
                test: /\.css$/,
                use: [
                    {
                        loader:miniCssExtractPlugin.loader
                    },
                    'css-loader',
                    'postcss-loader'  
                ]
            },
            {
                test:/\.js$/,  //最后会打包进输出的js的文件,所以不需要配置路径
                use:[
                    {
                        loader:'babel-loader',
                        options:{
                            presets:[
                                `@babel/preset-env`
                            ]
                        },
                    }
                ]
            },
            {
                test: /\.(png|jpg)$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name: '[name].[hash:8].[ext]',
                    //不能通过名字添加路径,因为背景图片还会被css处理一次,会再添加上css的路径
                    //最后就会变成 css/img/big.1763821.png
                    outputPath:'img/',  //通过该属性设置,打包输出的路径多一层
                    publicPath:'http://cdn.com'  //图片的访问路径为 http://cdn.com/img/big.561361.png
                },
                
            },
            {
                test:/\.html$/,
                loader:'html-withimg-loader',  //会加上url-loader里的outputPath
            }
        ]
    },
    plugins: [
        new htmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new miniCssExtractPlugin({
            filename:'css/[name].css'  //通过名字添加一层路径
        }),
        new cleanWebpackPlugin()
    ]
}

最终npm run build后,就可以有不同的文件夹,同时index.html也正确处理了路径。