webpack是前端资源模块化管理和打包工具。它将很多单独,松散的模块按照一定的规则和依赖打包成符合生产环境部署的资源。它可以进行代码转换,文件优化,代码分割,模块合并,自动刷新,自动发布等多种功能。

  webpack中主要用到CommonJS和ES6Module。CommonJS定义的是模块的同步加载,它一般应用于服务器的开发,像node.js,而ES6Module,它是js官方标准模块定义的方式。webpack在代码解析的时候支持两种规范的解析。二者的导入和导出方式如下:

/* ES6Module
 * 导出: export,export default(默认)
 * 导入: import
 */

//文件名:a.js
//代码如下:
function sum(a, b) {
    return a + b
}
//使用export导出时要记得使用{}
export { sum };
//使用export default导出时,后面不用再加上{}
export default sum

//文件名:b.js
//使用import导入时要记得变量名要写在{}中,要和导出一致,from后接的是相对路径
import { sum } from './a';
//可以在b.js中调用sum方法
console.log(sum(1, 2));
//导入,对应exprot default.import后面不用跟{},可以随意取变量名
import A from './a';
console.log(sum(3, 2));

  需要注意的是:模块的导入要放在代码的最前面,而且浏览器不能直接识别,需要先进行编译才可以。  

/* 
 * CommonJS模块化
 *      导出:module.exports = {属性名:属性值}
 *      导入:let/const exports导出的对象名 = require('文件名')
 */ 
 //a.js
 function sum(x,y){
    return x+y
}

module.exports = {
    sum:sum,//简写sum
}

//b.js
// 导入:
let s = require('./a');
console.log(s);

  webpack中一共有以下几个概念:

  入口(entry):它指示webpack应该使用哪个模块来作为构建其内部依赖图的开始。默认为:./src也可以通过配置entry中的属性来指定入口起点(一个或者多个)。。

  出口(output):它告诉webpack在哪时输出所创建的bundles,以及如名命名。默认为./dist。它也是可以配置多输口的。

  loader:模块转换,把模块原内容按照需求转换成新内容,可以加载非js的模块。本质上webpack loader将所有类型的文件转换为应用程序的依赖图可以引用的模块

  插件(plugins):扩展插件,在webpack构建流程中的特定时机注入扩展逻辑来改变构建的结果。它们都是可以进行配置的。想要使用一个插件,只需要用到require()它,然后把它添加到plugins数组中。多数插件是可以通过option来自定义选项的。

  模式(mode):通过development或production之中的任何一个来设置mode参数用以启用相应模式下webpack内置的优化。

  一、webpack的安装与基本使用

  目前我们一般采用的都是webpack4.0以上的版本,它支持零配置的使用。

  安装webpack,为了防止全局安装webpack导致的版本冲突,所以以本地安装为主。

  步骤一:新建一个文件夹,文件夹不能有特殊的字符。如:中文,特殊符号且名字不能是webpack否则会报错

  步骤二: 生成package.json文件。命令:npm init -y

  命令:npm i(install) webpack webpack-cli --save -dev   / npm i webpack webpack-cli -g

  步骤三:零配置使用。新建一个src文件夹,默认会打包src(当前项目开发的源代码)目录中的文件(入口默认为index.js),打包完成后的目录是dist/main.js编译后的文件。

  1、新建src目录且在src下分别创建a.js和index.js文件,代码如下:

/* src/a.js */
function sum(x,y){
    return x+y;
}

export {sum};

/* src/index.js */

import { sum } from './a.js'
console.log(sum(1, 4));

  2、进行打包处理,由于npm没有安装在全局不能使用命令,所以有两种方法。一种是使用:npx webpack。第二种是修改package.json中的script配置。就可以用npm run server 命令了。如下:

{
    "scripts":{
        "serve":"webpack"
    }
}

  3、我们可以看到项目的目录如下:

   4、如果不能使用零配置,可以自己来进行配置,自定义基础配置。

    4.1 新建一个webpack.config.js或者是webpackfile.js的文件。由于webpack分为开发环境和生产环境,所以我们可以创建三个不同的config.js进行不同的配置。

    webpack.config.js中可以进行entry,output,mode等基础的配置。需要注意一点的是在output中编译后的文件名要加上hash值,用以保证每次生成的文件是不一样的,好清除强缓存。且输出的目录是一个绝对的路径,所以要用到node.js 中的path。

const path = require('path');
 module.exports = {
     //设置编译的模式:development production(默认的)
     mode:'production',
     //设置编译的入口文件(真实项目中一般开发的代码都要放在src下)
     entry:'./src/main.js',
     //设置编译的出口文件
     output:{
         filename:'bundle.[hash:10].main.js',
         path:path.resolve(__dirname,'build')
     }
 }

  4.2  可以还新建两个不同的文件webpack.config.dev.js 和webpack.config.pro.js用来区分不同的环境所需要的不同内容。在package.confg.js中写两个环境都需要的内容。在package.json中进行配置。

  "scripts": {
    "serve":"webpack --config webpack.config.dev.js",
    "build":"webpack --config webpack.config.pro.js"
  },

   4.3  进行基本的自动化配置。

    利用html-webpack-plugin。这样每一次代码更改,复新编译过后,就不需要手动的去更改html中导入的js信息。命令:npm i html-webpack-plugin --save-dev进行下载;

    利用clean-webpack-plugin在每一次打包的时候都把之前打包的内容进行清空,即build下只保留最新的打包文件。命令:npm i clean-webpack-plugin --save-dev进行下载;

    利用webpack-dev-server可以创建一个web服务来自动监听代码的改变,自动编译,自动打开浏览器渲染页面。命令:npm i webpack-dev-server --save-dev进行下载。

   在配置html-webpack-plugin插件的时候需要注意的是路径的正确性,还有hash值是可以用来清除强缓存的,与output设置hash值是一样的,它也是可以进行配置。还可以把模板中的html代码进行压缩处理。

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
    plugins: [
        //配置指定的html模板
        new HtmlWebpackPlugin({
            //路径
            template: './public/index.html',
            //文件名
            filename: 'index.html',
            //设置hash值
            hash: true,
            //把模板中的html代码进行压缩
            minify: {
                collapseWhitespace: true,
                removeComments: true,
                removeAttributeQuotes: true,
                removeEmptyAttributes: true
            }
        }),
        //每一次打包把之前的都清空
        new CleanWebpackPlugin()
    ]
}

  在配置dev-server时编译好的结果是放在计算机内存中并不会像之前那样编译出现在build下。需要注意的一点是要把webpack.json中script中的配置进行修改。

// webpack.config.js
module.exports = {
    devServer:{
        port:'8080',
        compress:true,
        contentBase:path.resolve(__dirname,"build"),
        open:true,
        hot:true
    }
}
// package.json
"scripts": {
    "serve": "webpack-dev-server --open Chrome",
    "build": "webpack"
  }

  4.4  当我们有多入口,需要有多输口进行输出这样的需求时,这时,我们就要进行一系列的设置,配置多页面模板。

const path = require('path');
//配置多页面模板
const htmlPlugins = ['index','login'].map(item=>{
    return new HtmlWebpackPlugin({
        template: `./public/${item}.html`,    
        filename: `${item}.html`,
        chunks:[item],//指定当前页面中的依赖项
        hash: true,
        minify: {
            collapseWhitespace: true,
            removeComments: true,
            removeAttributeQuotes: true,
            removeEmptyAttributes: true
        }
    });
});
module.exports = {
    //多入口 => key:value
    entry: {
        index:'./src/main.js',
        login:'./src/login.js'
    },
    output: {
        //[name]多入口中配置的属性名 index/login
        filename: '[name].[hash:10].min.js',
        //输出的目录(需要的是绝对路径)
        path: path.resolve(__dirname, 'build')
    },
    plugins: [
        //配置指定的html页面模板
        ...htmlPlugins,   
    ]
}

  5.  webpack中的loader加载器。它可以用来处理css,less,图片,字体等等资源。

    5.1  处理css和less文件。使用之前必须先进行下载安装要用到style-loader、css-loader、less-style-loader,autoprefixer postcss-loader。命令:npm install css-loader style-loader less-loader autoprefixer postcss-loader --save -dev。

    style-loader把处理好的css以内嵌的方式插入到页面中;css-loader用来处理import这类语法,postcss-loader处理兼容性问题它需要和autoprefixer一起使用,在配置时,它还需要新建一个postcss.config.js的文件来添加配置,当然还需要在package.json中进配置。

    由于使用style-loader后css的引入是内嵌式的,这时就不是很方便,想要更好处理html中引入的css文件,还需要用到mini-css-extract-plugin来抽离css的内容。需要用到命令npm i mini-css-extract-plugin --save-dev进行下载和安装。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//webpack.config.js中
module.exports = {
    plugins: [
        //=>使用插件
        new MiniCssExtractPlugin({
            //=>设置编译后的文件名字
            filename: 'main.[hash:10].css'
        })
    ],
    // 配置loader
    module: {
        rules: [
            {
                //基于正则来查看匹配哪些文件
                test: /\.(css|less)$/i,
                use: [
                    // "style-loader",
                    // 如果要把css分离出来style-loader了,而写下面这一个loader 它替代了style方式
                    MiniCssExtractPlugin,
                    "css-loader",
                    "postcss-loader",
                    "less-loader",

                ]
            }
        ]
    }
}

//package.json中浏览器的兼容配置
"browserslist": [
    ">0.1%",
    "last 2 versiions"
]

//新生成的postcss.config.js中
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

  还可以使用optimize,uglifyjs或者是terser插件来优化压缩css和js文件,下面采用的是terser

  命令:npm install optimize-css-assets-webpack-plugin terser-webpack-plugin --save -dev

  配置:

const TerserWebpackPlugin  = require('terser-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
    //配置webpack优化项
    optimization:{
        //设置压缩方式
        minimizer:[
            new OptimizeCssAssetsWebpackPlugin(),
            new TerserWebpackPlugin()
        ] 
    }
}

  5.2  处理图片,字体文件

  在真实的项目中图片应用的位置在三处:css中的背景图,js中动态创建图片,html中直接写入图片

  命令:npm install file-loader url-loader html-withimg-loader --save-dev

module.exports = {
    module: {
        //=>模块规则:使用加载器(默认从右向左执行)
        rules: [{
            test: /\.(png|jpe?g|gif)$/i,
            use: [{
                //=>把指定大小内的图片BASE64
                //=>不在指定范围的采用file-loader进行处理
                loader: 'url-loader',
                options: {
                    limit: 200 * 1024,
                    outputPath:'/images',
                    //name:'[name].[ext]'
                }
            }],
            include: path.resolve(__dirname, 'src'),
            exclude: /node_modules/
        }, {
           test:/\.(svg|eot|ttf|woff|woff2)$/i,
           use:"file-loader"
        }, {
            test: /\.html$/,
            use: ['html-withimg-loader']
        }]
    }
}

 5.3 基于babel实现es6的转换和esList语法检测

  安装包依赖

  命令:$ npm install babel-loader @babel/core @babel/preset-env  –save-dev

  对于现在的开发来说,还有更高级的js语法如es7,8需要进行转换,所以还需要另外包的依赖和插件配置。一般要用到以下插件,先进行下载

  命令:$ npm install @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime –save-dev 

  在真实的目中我们还会安装@babel/polyfill来进行兼容的处理。它和其它的webpack加载器插件不一样,其它是编译时进行处理,而polyfill是运行时处理。 在代码运行时,把一些es7等特殊语法进行兼容处理,它需要安装在生产环境下。也需要@babel/plugin-transform-runtime插件的支持。在真实的项目中我们还会安装一个ESLint 来进行词法解析。

  命令:npm i @babel/runtime @babel/polyfill   npm i eslint eslint-loader -save-dev

  综上配置如下:

module.exports = {
    module: {
        rules: [{
            test: /\.js$/,
            use: [{
                loader: 'babel-loader',
                options: {
                    //=>转换的语法预设(ES6->ES5)
                    presets: [
                        "@babel/preset-env"
                    ],
                    //=>基于插件处理ES6/ES7中CLASS的特殊语法
                    plugins: [
                        ["@babel/plugin-proposal-decorators", {
                            "legacy": true
                        }],
                        ["@babel/plugin-proposal-class-properties", {
                            "loose": true
                        }],
                        "@babel/plugin-transform-runtime"
                    ]
                }
            }], //=>, "eslint-loader"
            //=>设置编译时忽略的文件和指定编译目录
            include: path.resolve(__dirname, 'src'),
            exclude: /node_modules/
        }]
    }
}

 

 

  

 

  

     

 

 

  

  

 

posted on 2020-07-18 22:13  人称小小贩  阅读(152)  评论(0编辑  收藏  举报