一、Webpack基本配置及使用

一、Webpack基本配置及使用

1、安装本地Webpack

webapck webpack-cli -D
// -D 表示上线不需要打这个包

// 初始化一下,记录安装的依赖
yarn init -y

// 5.2支持的npx语法可以直接执行webpack
// 默认去找node_modules下面的bin文件里面的webpack.cmd
npx webpack

2、 Webpack可以0配置

打包工具 -> 输出后的结果(js模块)

打包 -> 支持js模块化

// 执行这行命令,即可打包出一个main.js文件
npx webpack

提示需要配置mode

3、手动配置Webpack

1. 简单示例

默认配置文件的名字:webpack.config.js

// webpack 是 node 写出来的 所以要用node的写法来运行
const path = require('path');
// 这是一个导出的配置文件
module.exports = {
  mode: 'development', // 模式(两种):production development
  entry: './src/index.js', // 入口
  output: { // 出口
    filename: 'bundle.js', // 打包后的文件名
    path: path.resolve(__dirname, 'dist') // 路径(必须是一个绝对路径),__dirname不加也可以
  }
}

// 结果:会在根目录下有一个 dist/bundle.js 文件
// 可以在浏览器环境中运行即可

简易示例文件

// src/index.js
let str = require('./a.js');
console.log(str);

// src/a.js
module.exports = 'hello';

打包后的结果

// dist/bundle.js
(() => {
  var __webpack_modules__ = {
    "./src/a.js": // key -> 模块的路径
    (module) => { // value -> 函数
      eval(
        "module.exports = 'hello'\n\n//# sourceURL=webpack://practise/./src/a.js?"
      );
    },

    "./src/index.js":
    (
      __unused_webpack_module,
      __unused_webpack_exports,
      __webpack_require__
    ) => {
      eval(
        'let str = __webpack_require__("./src/a.js")\r\n\r\nconsole.log(str)\n\n//# sourceURL=webpack://practise/./src/index.js?'
      );
    },
  };
  // 定义了一个缓存[如果模块加载完了,不需要再次加载,从缓存中取出即可]
  var __webpack_module_cache__ = {};
  // 配置实现require方法(因为require无法在浏览器中运行)
  function __webpack_require__(moduleId) {
    var cachedModule = __webpack_module_cache__[moduleId];
    // 检查模块在不在缓存中,如果在缓存中,直接返回模块
    if (cachedModule !== undefined) {
      return cachedModule.exports;
    }
    // 安装一个模块[key: Object]
    var module = (__webpack_module_cache__[moduleId] = {
      exports: {},
    });
    // 通过key找到对应函数并执行
    __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
    // 返回对应的module.exports即可
    return module.exports;
  }
  var __webpack_exports__ = __webpack_require__("./src/index.js"); // './src/index.js': 入口模块
})();

2. 修改配置文件名

如果想要将配置文件名修改,如:webpack.config.my.js ,此时打包抛出异常

image.png

但是我们希望可以找到我们的配置文件。可以这样做:

npx webpack --config webpack.config.my.js

但是为了更方便,我们可以在 package.json 中进行配置:

{
    //...
    "scripts": {
        "build": "webpack --config webpack.config.my.js"
     }
    //...
}

执行 npm run buildyarn build 即可,其他类似。

但是下面这样写是需要注意的:

"scripts": {
    "build": "webpack"
}

// 它并不是一个参数,不会识别config后面的内容
npm run build --config webpack.config.my.js
yarn build --config webpack.config.my.js // yarn命令是可以的

// 如果一定要这样写,可以使用下面这种方式
npm run build -- --config webpack.config.my.js

3. 本地开发服务(通过ip访问)[webpack-dev-server]

webpack-dev-server

// 可通过 npx webpack-dev-server 开启,也可配置脚本

// package.json
"scripts": {
    "dev": "webpack-dev-server"
}

// webpack.config.js
module.exports = {
    // ...
    devServer: { // 开发服务器的配置
        port: 3000, // 端口号配置
        progress: true, // 可以看到打包进度条
        contentBase: './dist', // 指向打包目录,希望以这个目录作为静态服务
        compress: true // 启动gzip压缩
    }
    // ...
}

由于高版本的 webpack 与 webpack-dev-server 的兼容问题,如果不成功,可以修改脚本如下:

// package.json
"scripts": {
    "dev": "webpack serve"
}

4. 使用模板自动插入脚本[html-webpack-plugin]

html-webpack-plugin

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 这是一个类

module.exports = {
    // ...
    output: { // 出口
        filename: 'bundle.[hash].js', // 打包后的文件名,这里也加个hash避免缓存
        // filename: 'bundle.[hash:8].js', // 打包后的文件名,这里也加个hash避免缓存:hash只要8位
        path: path.resolve(__dirname, 'dist') // 路径(必须是一个绝对路径),__dirname不加也可以
    },
    plugins: [ // 数组:放着所有的webpack插件
        new HtmlWebpackPlugin({
            template: './src/index.html', // 模板
            filename: 'index.html', // 打包后的文件名
            minify: {
                removeAttributeQuotes: true, // 删除属性双引号
                collapseWhitespace: true // 折叠空行,变成一行
            },
            hash: true // 避免缓存问题,加上hash戳
        })
    ]
    // ...
}

5. 样式处理

Webpack默认只支持 JS 模块,所以对于 CSS ,需要特殊处理。

yarn add css-loader style-loader -D

yarn add less less-loader -D

...

// webpack.config.js
module.exports = {
    // ...
    module: { // 模块
        rules: [ // 规则
            {
                // css-loader: 解析 @import 这种语法的
                // style-loader: 把css插入到head的标签中
                // loader特点:希望单一
                // loader的用法:字符串只用一个loader
                // 多个loader需要数组
                // loader的顺序:默认从右向左、从下到上执行
                // loader还可以写成对象的形式
                test: /\.css$/,
                use: [
                    {
                        loader: 'style-loader',
                        options: {
                            // insertAt: 'top' // css的样式插入到顶部,避免head中的style被覆盖
                            // insertAt 已废弃
                            insert: () => {

                            }
                        }
                    },
                    'css-loader'
                ]
            },
            {
                // 处理less文件
                // 还有 sass stylus, 类似的处理方式
                // sass -> node-sass sass-loader
                // stylus -> stylus-loader
                test: /\.less$/,
                use: [
                    {
                        loader: 'style-loader',
                        options: {
                            // insertAt: 'top' // css的样式插入到顶部,避免head中的style被覆盖
                            // insertAt 已废弃
                            insert: () => {

                            }
                        }
                    },
                    'css-loader', // 解析 @import 这种语法的
                    'less-loader' // less -> css
                ]
            }
        ]
    }
    // ...
}

1. CSS抽离成单独的文件

mini-css-extract-plugin

yarn add mini-css-extract-plugin -D

// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    plugins: [ // 数组:放着所有的webpack插件
        new MiniCssExtractPlugin({
            filename: 'main.css' // 抽离css的文件名
        })
    ],
    module: { // 模块
        rules: [ // 规则
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            },
            {
                test: /\.less$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader', // 解析 @import 这种语法的
                    'less-loader' // less -> css
                ]
            }
        ]
    }
}

2. 自动添加浏览器前缀

yarn add postcss-loader autoprefixer -D

配置如下:

// webpack.config.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader'
                ]
            },
            {
                test: /\.less$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader',
                    'less-loader'
                ]
            }
        ]
    }
}

但是我们要告诉webpack我们要使用 autoprefixer, 所以需要在根目录(webpack.config.js 同级目录)新建一个 postcss.config.js 文件:

// postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

如果以上未生效,在 package.json 文件中增加如下配置:

// package.json
{
    // ...
    "browserslist": [
        "last 2 versions",
        "> 1%",
        "iOS 7",
        "last 3 iOS versions"
    ]
    // ...
}

3. CSS 压缩

optimize-css-assets-webpack-plugin

配置如下:

// webpack.config.js
module.exports = {
    // ...
    optimization: { // 优化项
        minimizer: [
            new OptimizeCssAssetsWebpackPlugin()
        ]
    }
    // ...
}

但是,使用了这个插件,会导致 js 不会被压缩了,所以必须配合使用另外一个插件:

uglifyjs-webpack-plugin

// webpack.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')

module.exports = {
    // ...
    optimization: { // 优化项
        minimizer: [
            new UglifyjsWebpackPlugin({
                cache: true, // 是否使用缓存
                parallel: true, // 是否是并发打包,可以同时打多个
                sourceMap: true // 压缩完js,ES6变为ES6,需要一个源码映射
            }),
            new OptimizeCssAssetsWebpackPlugin()
        ]
    },
    // ...
}

6. 转换ES6语法

Babel

1. 基础语法

yarn add babel-loader @babel/core @babel/preset-env -D

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
                    options: {
                        presets: [
                            '@babel/preset-env' // 把es6转换为es5的模块
                        ]
                    }
                }
            }
        ]
    }
    // ...
}

2. class

yarn add @babel/plugin-proposal-class-properties -D

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
                    options: {
                        presets: [
                            '@babel/preset-env' // 把es6转换为es5的模块
                        ],
                        plugins: [
                            '@babel/plugin-proposal-class-properties'
                        ]
                    }
                }
            }
        ]
    }
    // ...
}

3. 装饰器

yarn add @babel/plugin-proposal-decorators -D

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
                    options: {
                        presets: [
                            '@babel/preset-env' // 把es6转换为es5的模块
                        ],
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ["@babel/plugin-proposal-class-properties", { "loose" : true }]
                        ]
                    }
                }
            }
        ]
    }
    // ...
}

4. JS语法及校验

代码运行时的一个包。

1. generator、promise 等的处理

yarn add @babel/plugin-transform-runtime -D

yarn add @babel/runtime

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
                    options: {
                        presets: [
                            '@babel/preset-env' // 把es6转换为es5的模块
                        ],
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ["@babel/plugin-proposal-class-properties", { "loose" : true }],
                            "@babel/plugin-transform-runtime"
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'), // 包括,只要这个目录下的
                exclude: /node_modules/ // 排除这个目录下面的
            }
        ]
    }
    // ...
}
2. 实例方法不会被解析的处理

如 includes。

yarn add @babel/polyfill

3. JS语法校验

ESLint

yarn add eslint eslint-loader -D

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.js$/, // 可以同时写多个
                use: {
                    loader: 'eslint-loader',
                    options: {
                        enforce: 'pre' // previous 强制在其他的loader之前执行   
                    }
                }
            },
            {
                test: /\.js$/,
                // ...
            }
        ]
    }
    // ...
}

7. 全局变量的引入(三种方式)

1. expose-loader

2. ProvidePlugin

3. 引入不打包(externals)

expose-loader

暴露全局的loader 内联的loader

yarn add expose-loader

用法:

// 1、 内联的方式
import $ from 'expose-loader?$!jquery'
console.log(window.$)


// 2、配置到webpack.config.js中的方式,并且引入使用
import $ from 'jquery'
// ----
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: require.resolve('jquery'),
                use: 'expose-loader?$'
            }
        ]
    }
    // ...
}

// 3、配置到webpack.config.js中的方式
// webpack.config.js
const webpack = require('webpack');
module.exports = {
    // ...
    plugins: [
        new webpack.ProvidePlugin({ // 在每个模块中都注入 $。 [但是这样 window.$ 拿不到]
            $: 'jquery'
        })
    ]
    // ...
}

注意

externals

// webpack.config.js
const webpack = require('webpack');
module.exports = {
    // ...
    externals: { // 意义:这个模块是外部引入的,不需要打包
        jquery: '$'
    }
    // ...
}

8. 图片处理

1. 在JS中创建图片引入(new Image())

yarn add file-loader -D

file-loader 默认会在内部生成一张图片到打包后的目录下,把生成的图片的名字返回回来

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.(jpg|png|gif|jpeg)$/,
                use: 'file-loader'
            }
        ]
    }
    // ...
}

2. 在CSS中引入(background('url'))

css-loader 已支持

3. 在html中引入(

yarn add html-withimg-loader -D

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.html$/,
                use: 'html-withimg-loader'
            }
        ]
    }
    // ...
}

4. base64转换图片

当图片大于某个限制大小时,使用file-loader产出一个文件。但是小于这个限制值的时候,可以用base64来转化。

可以不用发起http请求去加载图片。

yarn add url-loader -D

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.(jpg|png|gif|jpeg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        esModule: false,
                        limit: 100 * 1024 // 图片小于100k,就使用base64,否则用file-loader产生真实的图片
                    }
                }
            }
        ]
    }
    // ...
}

9. 打包文件分类

1. 图片目录

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.(jpg|png|gif|jpeg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        esModule: false,
                        limit: 1,
                        outputPath: 'img/' // 打包到打包路径下的 img 目录中
                    }
                }
            }
        ]
    }
    // ...
}

但是引用是希望引用域名下这个目录对应的文件:

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 这是一个类

module.exports = {
    // ...
    output: { // 出口
        filename: 'bundle.[hash:8].js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: 'http://127.0.0.1:5500/dist' // 加这样一个域名
    }
    // ...
}

但是只想给图片加上这个域名,就可以这样做:

// webpack.config.js
module.exports = {
    // ...
    output: { // 出口
        filename: 'bundle.[hash:8].js',
        path: path.resolve(__dirname, 'dist')
    }
    // ...
    module: {
        rules: [
            {
                test: /\.(jpg|png|gif|jpeg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        esModule: false,
                        limit: 1,
                        outputPath: 'img/',
                        // 加这样一个域名,并且需要拼接上上面的输出目录
                        publicPath: 'http://127.0.0.1:5500/dist/img'
                    }
                }
            }
        ]
    }
    // ...
}

2. 样式目录

// webpack.config.js
module.exports = {
    // ...
    plugins: [ // 数组:放着所有的webpack插件
        new MiniCssExtractPlugin({
            filename: 'css/main.css'
        })
    ]
    // ...
}

你可能感兴趣的:(一、Webpack基本配置及使用)