webpack4.0的学习笔记

323 阅读8分钟

第一篇、webpack的安装与在项目中的使用

首先,在项目目录中执行 npm init -y (-y代表默认选项,可以不要-y自行配置)

然后安装 webpackwebpack-cli

npm i webpack webpack-cli -D

到这里 webpackwebpack-cli 就安装完成了

接下来可以在目录下新建一个 src 目录

src 目录中写我们的业务逻辑代码

例如新建一个 index.js ,写一个 Hello World

console.log('Hello World!')

然后在终端中执行 npx webpack ,它会将我们 src 中的代码进行打包,生成一个 dist 目录,该目录下会有一个 main.js ,然后我们在 dist 目录下新建一个 index.html 文件,引入 main.js ,浏览器打开该 index.html ,在控制台中可以看到 Hello World! 的输出

或者使用下面这种方式

当然你也可以在 src 中新建一个 a.js ,在 a.js 中写入如下代码

module.exports = 'joker'

然后在 src 下的 index.js 中引入该 a.js

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

然后再次执行 npx webpack ,在 index.html 引入生成的 main.js 它也可以输出 Hello World!

webpack 可以帮我们解析 js 的模块,并且以当前 js 为准,查找所有的依赖,打包成一个文件,而且解决了浏览器的require的问题,webpack自己实现了一套模块化的机制。

第二篇、手动配置webpack

需要在根目录下新建一个 webpack.config.js 文件(文件名尽量不要改动)

配置如下内容

// webpack 是 node 写的
let path = require('path');//引入node.js的path模块
module.exports = {
    mode:'none',//模式 production | development | none
    entry:'./src/index.js',//入口文件(你写的业务代码)
    output:{
        filename:'bundle.js',//打包后的文件名
        path:path.resolve(__dirname,'dist'),//路径必须是一个绝对路径(打包在根目录下生成一个dist目录)
    }}

这样配置之后,当我们再次执行 npx webpack 的时候,依然会生成一个 dist 目录,但是 dist 目录下的 main.js 变成了 bundle.js

这里我们看一下为什么配置文件名字只能叫 webpack.config.js

打开 node_modules --> webpack-cli --> bin --> config --> config-yargs.js 文件

在79行附近,会看到如下代码

config: {
      type: "string",
      describe: "Path to the config file",
      group: CONFIG_GROUP,
      defaultDescription: "webpack.config.js or webpackfile.js",//这里配置了webpack的配置文件的文件名,一般会选择第一个
      requiresArg: true
},

  • 如果修改了 webpack.config.js 的文件名,再次执行 npx webpack 应该写成后面这种形式 npx webpack --config webpack.config.my.js(这是新的webpack.config.js的文件名) 
  • 当然了,还有另一种办法执行 npx webpack 打包命令,打开 package.json 文件,写下如下脚本

"scripts":{
    "build":"webpack.config.my.js"//新的webpack.config.js的文件名,注意:如果改了文件名,值用新的文件名,如果没改,直接写入webpack即可
},

但是执行打包的时候就不再使用npx webpack 了,而使用这里配置的脚本 npm run build 进行打包

第三篇、html插件html-webpack-plugin

这里我们有个需求是我们所有的代码写在src下面,当我们执行npm run dev 命令的时候,实现本地服务器访问默认 index.html

首先我们需要先 npm i html-webpack-plugin 安装 html插件

然后在 webpack.config.js 中引入

let HtmlWebpackPlugin = require('html-webpack-plugin');//引入html插件
module.exports = {
    devServer:{//开发服务器的配置
        port:3000,//端口
        progress:true,//查看进度
        contentBase:'./build',//访问目录
        compress:true,//gzip压缩
    },
    plugins:[//数组,放着所有的webpack插件
        new HtmlWebpackPlugin({
            template:'./src/index.html',//入口html
            filename:'index.html',//打包之后的文件名
            minify:{
                removeAttributeQuotes:true,//删除html中的双引号
                collapseWhitespace:true,//折叠为一行
            },
            hash:true//hash戳
        })
    ]}

这样配置完了之后还得在 package.json 中配置

"scripts": {
    "build": "webpack --config webpack.config.js",//之前配置过的打包命令 npm run build
    "dev": "webpack-dev-server",//现在配置的运行命令 npm run dev
    "test": "echo \"Error: no test specified\" && exit 1"
  },

注意:必须再使用 npm i webpack-dev-server -D 这个命令安装这个插件,否则项目 npm run dev 启动不了。

这样之后,我们配置html插件就到此结束了,在终端中执行 npm run dev 就可以访问 src 目录下的 index.html 文件

这里又会出现一个问题,当多次打包时,bundle.js 会被覆盖,那怎么解决这个问题呢?很简单,只需要修改 package.jsoutput 的内容即可

output:{
    filename:'bundle.[hash:8].js',//打包后的文件名,hash指的是每次生成的文件名不一样,防止覆盖,:8指的是只显示8位
    path:path.resolve(__dirname,'dist'),//路径必须是一个绝对路径
},

这样子每次打包生成的 dist 目录下的 bundle.js 就会不同

第四篇、css的引入css-loader

这里我们先在根目录下新建 index.css 和 a.css 分别写下如下内容

/*index.css*/
@import './a.css'
body{
    background-color:red;
}

/*a.css*/
body{
    color:yellow;
}

如果我们要想引入这两个 css 文件,不能在 index.html 中直接引入,需要在 js 中当作模块来引入,打开 index.js 文件,引入 index.css

let str = require('./a.js')
require('./index.css')

单单这样引入还是不行的,我们还需要在 webpack.config.js 中进行配置模块

module:{//模块
    rules:[//规则
        // style-loader 他是吧css插入到head的标签中
        // loader的特点 希望单一
        // loader的用法 字符串 只用一个loader
        // 多个loader需要[]
        // loader的顺序 默认是从右向左执行,从上到下执行
        // loader还可以写成对象方式
        // {test: /\.css$/,user:['style-loader','css-loader']},
        {
            test:/\.css$/,//匹配所有的css文件
            use:[
                {
                    loader:'style-loader',//加载style-loader
                    //options选项可以省略
                    options:{
                        insert:'top',//将生成的css文件插入在head标签之上,可以使自己写在head标签内的style生效
                    }
                },
                'css-loader',//解析@important 和 css路径
            ]
        }
    ]}

最后安装一下依赖就大功告成了 npm i style-loader css-loader -D

这样子,我们就可以使用npm run dev 打开本地服务访问,并且可以成功引入css了,要注意的一点是,这里的css只能在JavaScript中以模块的方式引入

第五篇、css插件

这里我们可以看到前面使用的css是写在style标签内,如果样式特别多的话,会造成样式阻塞,我们现在要使用link标签引入css

首先我们需要先使用 npm i mini-css-extract-plugin -D 安装这个插件

然后在 webpack.config.js 中引入这个插件

let MiniCssExtractPlugin = require('mini-css-extract-plugin');//引入css抽离插件

众所周知,插件都是以构造函数的形式写在 plugins 中,所以:

plugins:[//数组,放着所有的webpack插件
    new MiniCssExtractPlugin({
        filename:'main.css',//抽离出来的css文件名
    })
],

注意,到这里还没有完哦~

接下来我们需要修改 webpack.config.jsmodule 里面的内容

module:{//模块
    rules:[
        {
            test:/\.css$/,
            use:[
                MiniCssExtractPlugin.loader,//将第四篇中这里的对象替换为MiniCssExtractPlugin.loader
                'css-loader',//解析@important 和 路径
            ]
        }
    ]}

到这里,我们再次执行 npm run build 就会看到给我们生成一个main.css,并且在 index.html 中使用 link 标签引入了该 css

但是我们再次在index.css中写下有兼容性的代码的时候,打包生成的main.css是没有前缀的,这时我们需要装一个css浏览器前缀的插件

首先执行 npm i postcss-loader autoprefixer -D 安装自动补齐浏览器前缀的插件

然后在 webpack.config.jsmodule 中添加 postcss-loader

module:{//模块
    rules:[
        {
            test:/\.css$/,
            use:[
                MiniCssExtractPlugin.loader,
                'css-loader',//解析@important 和 路径
                'postcss-loader',//添加上postcss-loader
            ] 
       }
    ]
}

只添加这个还是没有用的,需要再新建一个配置文件 postcss.config.js 

内容写下如下代码:

module.exports = {
    plugins:[
        require('autoprefixer')
    ]
}

然后再次执行 npm run build 打包就可以帮我们加上前缀了(有一说一,我没加上,不知道为啥)

接下来我们需要将打包的css和js一致,都是被压缩过的

首先使用 npm i optimize-css-assets-webpack-plugin -D 安装css压缩插件

然后在 webpack-config.js 中引入该插件

let OptimizeCss = require('optimize-css-assets-webpack-plugin');//引入css压缩插件

然后在 webpack.config.js 中使用这个插件

module.exports = {
    optimization:{//优化项
        minimizer:[
            new OptimizeCss()
        ]
    },
    ...
}

到这里之后,我们执行 npm run build ,没错 css 确实是被压缩了,可是js并没有被压缩

使用这个插件,我们还需使用 npm i uglifyjs-webpack-plugin -D 安装另一个插件来压缩js

安装完成之后,我们需要在 webpack.config.js 中进行引入和配置

let UglifyJsPlugin = require('uglifyjs-webpack-plugin');//压缩js插件
module.exports = {
    optimization:{//优化项
        minimizer:[
            new UglifyJsPlugin({
                chche:true,//是否允许缓存
                parallel: true,//是否并发打包(可以打包多个)
                sourceMap: true,//ES6转为ES5之后,方便调试,进行源码映射
            }),
            new OptimizeCss()
        ]
    },
    ...
}

这样完成之后,我们再次执行 npm run build 打包之后发现 cssjs 均被压缩

视频是这样说的,可是我这样做之后并没有给我压缩js文件,还给我报了个错,很郁闷,看看有没有大佬和我一样的


第六篇、babel的使用及更高级语法转换ES5

首先,我们在index.js中先写一段ES6语法,这里以箭头函数为例。

let fn = () => {
    console.log('Joker')
}
fn();

写完这个之后直接执行 npm run build 后打开 dist 目录下生成的 js 文件,查看源码

我们会在 96行 附近发现,我们写的ES6的箭头函数并没有被转换为 ES5 的语法,这是我们需要使用  npm i babel-loader @babel/core @babel/preset-env -D 命令安装插件来进行转换 

然后我们需要在 webpack.config.js 里面配置规则

rules:[//规则
    {
        test:/\.js$/,//匹配所有的js文件
        use:{
            loader:'babel-loader',
            options:{ //用babel-loader将ES6转为ES5
                presets:[//预设
                    '@babel/preset-env'
                ]
            }
        }
    },

完成之后,这时候我们再次打开 dist 目录下生成的 js 文件,查看源码,会发现在 96行 附近,我们的 ES6箭头函数 被转为 ES5 的var声明函数

如果ES6里面还有一些高级语法,类似于class类,这个插件就不能帮我们转码,这时候需要安装另一个插件

我们先在 index.js 中写下一个 class类

class A {
    a = 1;
}

当我们执行 npm run build 的时候,会报错。我们需要使用 npm i @babel/plugin-proposal-class-properties -D 命令安装插件来转码 class类

然后我们需要在 webpack.config.js 规则中配置插件

rules:[//规则
    {
        test:/\.js$/,//匹配所有的js文件
        use:{
           loader:'babel-loader',
           options:{
               presets:[//预设
                   '@babel/preset-env'
               ],
               plugins:[
                   "@babel/plugin-proposal-class-properties"
              ]
           }
        }
    },

这时候我们执行 npm run build 的时候就不会报错,为了能看到效果,在 index.js 中写下如下代码

class A {
    a = 1;
}
let a = new A();
console.log(a.a)

然后执行命令 npm run dev 在浏览器中打开控制台里能看到 1 说明这个插件就配置成功了,成功将 class类 转为了 ES5语法

当然了,还有另一种情况,class类的装饰器同样也不可以转码

这时候我们还需要安装另一个插件,具体步骤请看如下:

  • 使用  npm i @babel/plugin-proposal-decorators -D 命令安装插件
  • 去官网查看该如何配置babeljs.io/docs/en/bab…

打开 webpack.config.js ,将插件改写成如下代码:

rules:[//规则
    {
        test:/\.js$/,//匹配所有的js文件
        use:{
            loader:'babel-loader',
            options:{
                presets:[//预设
                    '@babel/preset-env'
                ],
                plugins:[
                    //根据babel官网配置如下内容
                    ["@babel/plugin-proposal-decorators", { "legacy": true }],
                    ["@babel/plugin-proposal-class-properties", { "loose" : true }]
                ]
            }
        }
    },

为了检验配置是否成功,我们打开 index.js 文件,将class类改写为如下代码:

@log //装饰器
class A { //class类
    a = 1;
}
let a = new A();//实例化
console.log(a.a)
function log(target){
    console.log(target + '20')
}

然后我们执行 npm run dev ,本地启动之后,可以看到控制台打印出来了装饰器里面的 target


未完待续...