Skip to content

全局变量引入

本节看一下webpack的第三方模块的使用。

比如jQuery,先来安装一下

shell
yarn add jquery@^3.4.1

jQuery是第三方模块,一般其他的第三方模块可能会依赖jQuery,可能是window上的jQuery,这时候应该怎么处理呢?

我们修改一下index.js文件

js
// webpack-dev-1\src\index.js
import $ from 'jquery'
console.log($);

使用import和require是一样的,相当于默认到处一个 $符。

我们运行一下试试,npm run dev

此时的配置文件 webpack.config.js

js
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件

let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件

module.exports = {
    // 配置优化项
    optimization: {
        minimizer: [ // 是一个数组,还得优化js
            new UglifyJsPlugin({
                cache: true, // 是否用缓存
                parallel: true, // 是否并发压缩
                sourceMap: true,// 线上用来调试的映射文件
            }),
            new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
        ]
    },

    devServer: { // 开发服务器的配置
        port: 3000, // 默认端口是8080,这里可以改
        progress: true, // 打包时候的进度条
        contentBase: './build', // 以哪个文件夹作为服务的根目录 
        open: true, // 服务启动完毕后,直接打开浏览器
        compress: true, // 启动gzip压缩

    },

    mode: 'development', // 模式,默认两种模式 production 和 development

    entry: './src/index.js', // 入口

    output: {
        filename: 'bundle.js', // 打包后的文件名
        path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
    },


    plugins: [ // 是一个数组,放着所有的webpack插件
        // 插件是一个类,通过new的方式来引用
        new HtmlWebpackPlugin({
            template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
            filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
            hash: true, // 引用的时候可以加一个hash戳
        }),
        // 插件的使用就没有先后顺序了,随便放就行
        // 引入抽离css样式的插件,
        new MiniCssExtractPlugin({
            filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
        }),
    ],

    module: { // 模块
        rules: [ // 规则,在这里面配置各种loader
            {
                test: /\.js$/, // 匹配以js结尾的文件
                use: {
                    loader: 'babel-loader',
                    options: { // 用babel-loader 需要把ES6转为ES5
                        // 配置可以写在这里,还可以写在外面
                        // 在这里添加一个预设
                        presets: [ // 这是一个大插件的集合
                            '@babel/preset-env', // 这个插件就可以把ES6转ES5
                        ],
                        // 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ['@babel/plugin-proposal-class-properties', { "loose": true }],
                            "@babel/plugin-transform-runtime"
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'), // 只找src目录下的js  包括
                exclude: /node_modules/ // node_modules文件夹下的文件不用找  排除
            },

            // css-loader 解析css文件,@import语法的
            // style-loader 把解析后的css文件 插入到head标签中
            // loader有个特点,希望单一,一个loader干一件事
            /* 
                loader的用法
                1. 只用字符串,就是只用一个loader
                2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
            */
            // loader的顺序,默认是从右向左执行,从下往上执行
            {
                test: /\.css$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                ]
            },
            {
                test: /\.less$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
                    // 这里就用一个了
                    'css-loader', // 解析 @import语法 解析 css
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                    'less-loader' // 把less 转换为 css
                ]
            },
        ],
    }
}

我们发现,正常打印了出来。

image-20220113104245819

如何拿到window.$

webpack默认封装的是一个闭包函数,这时候我们刚才引入的$并不会挂载到window上,我们改一下代码,看下效果

js
// webpack-dev-1\src\index.js
import $ from 'jquery'
console.log(window.$); // 试一下window.$

发现打印了undefined

image-20220113104611542

这时候怎么处理呢?我们希望这个变量可以暴露给window

使用 expose-loader,把变量暴露给window

有个 expose-loader,它的作用可以把引入的第三方模块,暴露给全局。

前面我们已经学习了三种loader

  1. pre,最前面执行的loader
  2. normal,普通的loader
  3. post,最后执行的loader

其实还有一种内联loader,可以直接在代码里加载这个loader,比如引入jquery时,我们使用 expose-loader,将$暴露给全局。

改写一下index.js代码

js
// webpack-dev-1\src\index.js
import $ from 'expose-loader?$!jquery'
// expose-loader?$!jquery 
// 内联loader
// 这句话的意思是,使用 expose-loader 将 导入的 jquery,变为 $ 符,然后暴露给 全局对象window

console.log(window.$); // 试一下window.$

安装一下 expose-loader,代码里需要,所以不带-D

shell
yarn add expose-loader@^0.7.5

安装完成之后,重新运行一下代码,npm run dev

image-20220113105435091

发现$已经暴露给全局对象window了,说明这个loader生效了。

如果感觉这种内联loader的写法很恶心,我们还可以直接配置到webpack的配置文件里

修改webpack.config.js文件

js
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件

let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件

module.exports = {
    // 配置优化项
    optimization: {
        minimizer: [ // 是一个数组,还得优化js
            new UglifyJsPlugin({
                cache: true, // 是否用缓存
                parallel: true, // 是否并发压缩
                sourceMap: true,// 线上用来调试的映射文件
            }),
            new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
        ]
    },

    devServer: { // 开发服务器的配置
        port: 3000, // 默认端口是8080,这里可以改
        progress: true, // 打包时候的进度条
        contentBase: './build', // 以哪个文件夹作为服务的根目录 
        open: true, // 服务启动完毕后,直接打开浏览器
        compress: true, // 启动gzip压缩

    },

    mode: 'development', // 模式,默认两种模式 production 和 development

    entry: './src/index.js', // 入口

    output: {
        filename: 'bundle.js', // 打包后的文件名
        path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
    },


    plugins: [ // 是一个数组,放着所有的webpack插件
        // 插件是一个类,通过new的方式来引用
        new HtmlWebpackPlugin({
            template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
            filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
            hash: true, // 引用的时候可以加一个hash戳
        }),
        // 插件的使用就没有先后顺序了,随便放就行
        // 引入抽离css样式的插件,
        new MiniCssExtractPlugin({
            filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
        }),
    ],

    module: { // 模块
        rules: [ // 规则,在这里面配置各种loader
            {
                // 这个规则表示,当我们在代码引用了 jquery时,使用该loader
                test: require.resolve('jquery'),
                use: 'expose-loader?$',
                // 表示当引用jquery时,把引用的结果 $ 暴露给 全局对象window
            },
            {
                test: /\.js$/, // 匹配以js结尾的文件
                use: {
                    loader: 'babel-loader',
                    options: { // 用babel-loader 需要把ES6转为ES5
                        // 配置可以写在这里,还可以写在外面
                        // 在这里添加一个预设
                        presets: [ // 这是一个大插件的集合
                            '@babel/preset-env', // 这个插件就可以把ES6转ES5
                        ],
                        // 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ['@babel/plugin-proposal-class-properties', { "loose": true }],
                            "@babel/plugin-transform-runtime"
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'), // 只找src目录下的js  包括
                exclude: /node_modules/ // node_modules文件夹下的文件不用找  排除
            },

            // css-loader 解析css文件,@import语法的
            // style-loader 把解析后的css文件 插入到head标签中
            // loader有个特点,希望单一,一个loader干一件事
            /* 
                loader的用法
                1. 只用字符串,就是只用一个loader
                2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
            */
            // loader的顺序,默认是从右向左执行,从下往上执行
            {
                test: /\.css$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                ]
            },
            {
                test: /\.less$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
                    // 这里就用一个了
                    'css-loader', // 解析 @import语法 解析 css
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                    'less-loader' // 把less 转换为 css
                ]
            },
        ],
    }
}

修改index.js

js
// webpack-dev-1\src\index.js
import $ from 'jquery'
console.log(window.$); // 试一下window.$

重新运行一下 npm run dev,发现也是正常挂载到了window上

image-20220113110050059

在每个模块中直接注入 $ 对象

如果不想挂载到全局中,我们希望直接在每个模块中注入 $ 对象,这时候就需要一个webpack的插件了。webpack.ProvidePlugin 插件。

修改webpack.config.js

js
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件

let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件
let webpack = require('webpack') // 使用webpack内置的插件

module.exports = {
    // 配置优化项
    optimization: {
        minimizer: [ // 是一个数组,还得优化js
            new UglifyJsPlugin({
                cache: true, // 是否用缓存
                parallel: true, // 是否并发压缩
                sourceMap: true,// 线上用来调试的映射文件
            }),
            new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
        ]
    },

    devServer: { // 开发服务器的配置
        port: 3000, // 默认端口是8080,这里可以改
        progress: true, // 打包时候的进度条
        contentBase: './build', // 以哪个文件夹作为服务的根目录 
        open: true, // 服务启动完毕后,直接打开浏览器
        compress: true, // 启动gzip压缩

    },

    mode: 'development', // 模式,默认两种模式 production 和 development

    entry: './src/index.js', // 入口

    output: {
        filename: 'bundle.js', // 打包后的文件名
        path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
    },


    plugins: [ // 是一个数组,放着所有的webpack插件
        // 插件是一个类,通过new的方式来引用
        new HtmlWebpackPlugin({
            template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
            filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
            hash: true, // 引用的时候可以加一个hash戳
        }),
        // 插件的使用就没有先后顺序了,随便放就行
        // 引入抽离css样式的插件,
        new MiniCssExtractPlugin({
            filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
        }),

        // webpack自带的插件,向每个模块注入一个对象
        new webpack.ProvidePlugin({
            $: 'jquery', // 相当于每个模块都被注入了一个 $ 对象, 可以直接使用
        }),
    ],

    module: { // 模块
        rules: [ // 规则,在这里面配置各种loader
            /* {
                // 这个规则表示,当我们在代码引用了 jquery时,使用该loader
                test: require.resolve('jquery'),
                use: 'expose-loader?$',
                // 表示当引用jquery时,把引用的结果 $ 暴露给 全局对象window
            }, */
            {
                test: /\.js$/, // 匹配以js结尾的文件
                use: {
                    loader: 'babel-loader',
                    options: { // 用babel-loader 需要把ES6转为ES5
                        // 配置可以写在这里,还可以写在外面
                        // 在这里添加一个预设
                        presets: [ // 这是一个大插件的集合
                            '@babel/preset-env', // 这个插件就可以把ES6转ES5
                        ],
                        // 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ['@babel/plugin-proposal-class-properties', { "loose": true }],
                            "@babel/plugin-transform-runtime"
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'), // 只找src目录下的js  包括
                exclude: /node_modules/ // node_modules文件夹下的文件不用找  排除
            },

            // css-loader 解析css文件,@import语法的
            // style-loader 把解析后的css文件 插入到head标签中
            // loader有个特点,希望单一,一个loader干一件事
            /* 
                loader的用法
                1. 只用字符串,就是只用一个loader
                2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
            */
            // loader的顺序,默认是从右向左执行,从下往上执行
            {
                test: /\.css$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                ]
            },
            {
                test: /\.less$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
                    // 这里就用一个了
                    'css-loader', // 解析 @import语法 解析 css
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                    'less-loader' // 把less 转换为 css
                ]
            },
        ],
    }
}

修改index.js

js
// webpack-dev-1\src\index.js
// 每个模块都被注入了一个 $ 对象
console.log($);

重新运行一下看下效果,npm run dev,发现正常打印出了结果,说明每个模块都被成功注入了

image-20220113110725339

不过此时,使用window.$就拿不到了,因为这种方式是在每个模块中都注入$对象。

使用cdn中引入

有时候我们会直接在index.html引入一个全局的jquery cdn,那么我们这个第三方的库就自动的挂载到了window上

修改index.html

html
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            background-color: pink;
        }
    </style>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>

修改index.js

js
// webpack-dev-1\src\index.js
// 在index.html 里 引入了cdn,理所应当的就能拿到$对象了
console.log(window.$);

修改配置文件

js
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件

let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件
let webpack = require('webpack') // 使用webpack内置的插件

module.exports = {
    // 配置优化项
    optimization: {
        minimizer: [ // 是一个数组,还得优化js
            new UglifyJsPlugin({
                cache: true, // 是否用缓存
                parallel: true, // 是否并发压缩
                sourceMap: true,// 线上用来调试的映射文件
            }),
            new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
        ]
    },

    devServer: { // 开发服务器的配置
        port: 3000, // 默认端口是8080,这里可以改
        progress: true, // 打包时候的进度条
        contentBase: './build', // 以哪个文件夹作为服务的根目录 
        open: true, // 服务启动完毕后,直接打开浏览器
        compress: true, // 启动gzip压缩

    },

    mode: 'development', // 模式,默认两种模式 production 和 development

    entry: './src/index.js', // 入口

    output: {
        filename: 'bundle.js', // 打包后的文件名
        path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
    },


    plugins: [ // 是一个数组,放着所有的webpack插件
        // 插件是一个类,通过new的方式来引用
        new HtmlWebpackPlugin({
            template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
            filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
            hash: true, // 引用的时候可以加一个hash戳
        }),
        // 插件的使用就没有先后顺序了,随便放就行
        // 引入抽离css样式的插件,
        new MiniCssExtractPlugin({
            filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
        }),

        // webpack自带的插件,向每个模块注入一个对象
        /* new webpack.ProvidePlugin({
            $: 'jquery', // 相当于每个模块都被注入了一个 $ 对象, 可以直接使用
        }), */
    ],

    module: { // 模块
        rules: [ // 规则,在这里面配置各种loader
            /* {
                // 这个规则表示,当我们在代码引用了 jquery时,使用该loader
                test: require.resolve('jquery'),
                use: 'expose-loader?$',
                // 表示当引用jquery时,把引用的结果 $ 暴露给 全局对象window
            }, */
            {
                test: /\.js$/, // 匹配以js结尾的文件
                use: {
                    loader: 'babel-loader',
                    options: { // 用babel-loader 需要把ES6转为ES5
                        // 配置可以写在这里,还可以写在外面
                        // 在这里添加一个预设
                        presets: [ // 这是一个大插件的集合
                            '@babel/preset-env', // 这个插件就可以把ES6转ES5
                        ],
                        // 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ['@babel/plugin-proposal-class-properties', { "loose": true }],
                            "@babel/plugin-transform-runtime"
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'), // 只找src目录下的js  包括
                exclude: /node_modules/ // node_modules文件夹下的文件不用找  排除
            },

            // css-loader 解析css文件,@import语法的
            // style-loader 把解析后的css文件 插入到head标签中
            // loader有个特点,希望单一,一个loader干一件事
            /* 
                loader的用法
                1. 只用字符串,就是只用一个loader
                2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
            */
            // loader的顺序,默认是从右向左执行,从下往上执行
            {
                test: /\.css$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                ]
            },
            {
                test: /\.less$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
                    // 这里就用一个了
                    'css-loader', // 解析 @import语法 解析 css
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                    'less-loader' // 把less 转换为 css
                ]
            },
        ],
    }
}

重新运行一下看下效果,npm run dev,发现可以的。

image-20220113111957516

因为是挂载到window上了,直接不带window肯定也是能访问到的。

但是有时候,虽然已经在全局引入了,我们有时候还是会在文件上面重新引入一份

修改index.js文件

js
// webpack-dev-1\src\index.js
import $ from 'jquery'
console.log($);
// 在index.html 里 引入了cdn,理所应当的就能拿到$对象了
// 但是有时候,我们还是会习惯在头部重新引用一份
// 这时候就坏了,相当于多引了一份

我们打包一下看下结果,npm run build

image-20220113112342165

发现打包后的文件足足有323KB大,肯定是多引了。

使用 externals ,配置无需打包的模块

上面的问题,可以通过配置 externals 属性来解决,这个配置告诉webpack,该模块是通过cdn引入的,无需打包

修改配置文件

js
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件

let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件
let webpack = require('webpack') // 使用webpack内置的插件

module.exports = {
    // 配置优化项
    optimization: {
        minimizer: [ // 是一个数组,还得优化js
            new UglifyJsPlugin({
                cache: true, // 是否用缓存
                parallel: true, // 是否并发压缩
                sourceMap: true,// 线上用来调试的映射文件
            }),
            new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
        ]
    },

    devServer: { // 开发服务器的配置
        port: 3000, // 默认端口是8080,这里可以改
        progress: true, // 打包时候的进度条
        contentBase: './build', // 以哪个文件夹作为服务的根目录 
        open: true, // 服务启动完毕后,直接打开浏览器
        compress: true, // 启动gzip压缩

    },

    mode: 'development', // 模式,默认两种模式 production 和 development

    entry: './src/index.js', // 入口

    output: {
        filename: 'bundle.js', // 打包后的文件名
        path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
    },


    plugins: [ // 是一个数组,放着所有的webpack插件
        // 插件是一个类,通过new的方式来引用
        new HtmlWebpackPlugin({
            template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
            filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
            hash: true, // 引用的时候可以加一个hash戳
        }),
        // 插件的使用就没有先后顺序了,随便放就行
        // 引入抽离css样式的插件,
        new MiniCssExtractPlugin({
            filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
        }),

        // webpack自带的插件,向每个模块注入一个对象
        /* new webpack.ProvidePlugin({
            $: 'jquery', // 相当于每个模块都被注入了一个 $ 对象, 可以直接使用
        }), */
    ],

    externals: { // 告诉webpack,不用打包的外部库,已经通过 cdn引入了
        jquery: '$'
    },

    module: { // 模块
        rules: [ // 规则,在这里面配置各种loader
            /* {
                // 这个规则表示,当我们在代码引用了 jquery时,使用该loader
                test: require.resolve('jquery'),
                use: 'expose-loader?$',
                // 表示当引用jquery时,把引用的结果 $ 暴露给 全局对象window
            }, */
            {
                test: /\.js$/, // 匹配以js结尾的文件
                use: {
                    loader: 'babel-loader',
                    options: { // 用babel-loader 需要把ES6转为ES5
                        // 配置可以写在这里,还可以写在外面
                        // 在这里添加一个预设
                        presets: [ // 这是一个大插件的集合
                            '@babel/preset-env', // 这个插件就可以把ES6转ES5
                        ],
                        // 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ['@babel/plugin-proposal-class-properties', { "loose": true }],
                            "@babel/plugin-transform-runtime"
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'), // 只找src目录下的js  包括
                exclude: /node_modules/ // node_modules文件夹下的文件不用找  排除
            },

            // css-loader 解析css文件,@import语法的
            // style-loader 把解析后的css文件 插入到head标签中
            // loader有个特点,希望单一,一个loader干一件事
            /* 
                loader的用法
                1. 只用字符串,就是只用一个loader
                2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
            */
            // loader的顺序,默认是从右向左执行,从下往上执行
            {
                test: /\.css$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                ]
            },
            {
                test: /\.less$/,
                use: [
                    // 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
                    MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
                    // 这里就用一个了
                    'css-loader', // 解析 @import语法 解析 css
                    // 应该在解析css之前增加前缀
                    'postcss-loader',
                    'less-loader' // 把less 转换为 css
                ]
            },
        ],
    }
}

重新打包看下结果,发现文件已经大大缩小了。只剩4KB了。

image-20220113112750371

总结

引入第三方模块的几种方式

  1. 使用 expose-loader,暴露到 window 上
  2. webpack.ProvidePlugin,给每个模块都注入一个
  3. 使用CDN引入,另外使用 externals配置不打包选项优化一下,防止重复引用导致打包体积过大。

参考

https://www.bilibili.com/video/BV1a4411e7Bz?p=9&spm_id_from=pageDriver