2.webpack的核心概念

2-1 loader
2-2使用loader打包静态文件
2-3 css模块化
2-4htmlWebpackPlugin
2-5 cleanWepackPlugin
2-6 entry和output
2-7 sourcemap
2-8 webpackDevServer
2-9 Hot Module Replacement
2-10 ES6语法转化

2-1loader

webpack只能默认处理js打包,打包其他的文件需要对应的loader(模块转换器),比如打包图片使用file-loader。
//webpack.config.js
const path = require('path')

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    module: {
        rules: [{
            test: /\.jpg$/,
            use: {
                loader: 'file-loader',
                options: {}
            }
        }]
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}

2-2使用loader打包静态文件

[file-loader链接](https://www.webpackjs.com/loaders/file-loader/) ```javascript //webpack.config.js const path = require('path')

module.exports = {
mode: ‘development’,
entry: {
main: ‘./src/index.js’
},
module: {
rules: [{
test: /(.jpg|png|gif)$/,
use: {
loader: ‘file-loader’,
//placehodles占位符
options: {’[name]_[hash].[ext]’},
outputpath: 'images/
}
}]
},
output: {
filename: ‘bundle.js’,
path: path.resolve(__dirname, ‘dist’)
}
}

## 样式文件打包
[loaders](https://www.webpackjs.com/loaders/)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200920234402735.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDQ5OTQ2NQ==,size_16,color_FFFFFF,t_70#pic_center)
css-loader:分析css文件之间的依赖。
style-loader:把css内容挂载到html的head上。
scss-loader node-sass:把scss文件转css
postcss-loader: 自动加厂商前缀,使用c3时需要
npm i autoprefixer -D

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

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: ['style-loader', 'css-loader', 'sass-loader', 'postcss-loader']
        }]
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}

2-3 css模块化

css模块化的原因

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="root"></div>
    <script src="./bundle.js"></script>
</body>
</html>

createAvatar.js

import avatar from './avatar.jpg'

function createAvatar () {
    var img = new Image();
    img.src = avatar;
    img.classList.add('avatar');

    var root = document.getElementById('root');
    root.append(img)
}

export default createAvatar;
//在这个文件中实例化了img标签
//index.js

var avatar = require('./avatar.jpg');
import './index.scss'
import createAvatar from './createAvatar';
**//执行createAvatar时会生成img标签,此时引入的index.scss会同时作用。
//所以相当于全局引用了,会污染代码,出现样式冲突问题,所以引入cssmodule**
createAvatar()
var img = new Image();
img.src = avatar.default;
img.classList.add('avatar');

var root = document.getElementById('root');
root.append(img);

//执行createAvatar时会生成img标签,此时引入的index.scss会同时作用。
//所以相当于全局引用了,会污染代码,出现样式冲突问题,所以引入cssmodule

css模块化的代码实现

const path = require('path')

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        }]
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}

上面在css-loader中加入了modules: true

var avatar = require('./avatar.jpg');
//1.引入index.css
import style from './index.scss';
import createAvatar from './createAvatar';

createAvatar()
var img = new Image();
img.src = avatar.default;
//2. style.avatar
img.classList.add(style.avatar);

var root = document.getElementById('root');
root.append(img);

2-4 htmlWebpackPlugin

  • 作用
    在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中。
const path = require('path')
// 引入HtmlWebpackPlugin
const 引入HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        }]
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 以src下的index.html为模板构建
            template: 'src/index.html'
        })
    ]
}

------plugins 可以在webpack运行的某个时刻的时候,帮你做一些事情------

2-5 cleanWepackPlugin

  • 作用
    能在打包的时候不用每次手动清除之前的打包遗留,让插件帮助我们完成,但是这不是webpack官方推荐的插件。
const path = require('path')
// 引入HtmlWebpackPlugin

const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        }]
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 以src下的index.html为模板构建
            template: 'src/index.html'
        }),
        // 使用此插件在我们打包前清除dist目录
        new CleanWebpackPlugin()
    ]
}

2-6 entry和output

const path = require('path')
// 引入HtmlWebpackPlugin

const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js',
        sub: './src/index.js'
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 以src下的index.html为模板构建
            template: 'src/index.html'
        }),
        // 使用此插件在我们打包前清除dist目录
        new CleanWebpackPlugin()
    ],
    output: {
        // filename: 'bundle.js',
        //配置cdn
        publicPath: 'http://cdn.com.cn',
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    }
}

在打包多个文件的时候,由于entry可以有多个但是output只有一个,所以,在打包多个的时候output要使用占位符进行打包,与打包出来的文件一一对应,由于配置了htmlWebpackPlugin,打包好的js文件会直接在index.html被引用。
publicPath配置:可以使html引用的js文件加上cdn前缀。

2-7 sourcemap

演示没有sourcemap的情况

conle.log('hello world');

故意写错代码

const path = require('path')
// 引入HtmlWebpackPlugin

const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
    mode: 'development',
    // 开发模式默认配置了sourcemap,现在手动关闭
    devtool: 'none',
    entry: {
        main: './src/index.js'
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 以src下的index.html为模板构建
            template: 'src/index.html'
        }),
        // 使用此插件在我们打包前清除dist目录
        new CleanWebpackPlugin()
    ],
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    }
    
}

开发模式默认配置了sourcemap,现在通过devtool: 'none’手动关闭
结果:在浏览器中查看错误的时候能看到打包后的文件里的错误,我们希望能够知道源代码里错误的位置。
sourcemap

  • 是一个映射关系,他知道dist目录下错误代码的位置对应了源代码的位置。
    把配置文件改为devtool: 'soruce-map’即可。
    此选项有很多配置,可参考devtool
    最佳实践
    开发环境: cheap-module-eval-source-map
    生成环境: cheap-module-source-map

2-8 webpackDevServer

在改了src目录下的源码码是dist目录能够自动打包,省去手动打包。实现这个有三种做法:
1.webpack --watch

{
    "name": "webpackDemo",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "bundle": "webpack",
        "watch": "webpack --watch"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "autoprefixer": "^8.6.5",
        "clean-webpack-plugin": "^3.0.0",
        "file-loader": "^6.1.0",
        "html-webpack-plugin": "^4.5.0",
        "postcss-loader": "^4.0.2",
        "style-loader": "^1.2.1",
        "webpack": "^4.44.2",
        "webpack-cli": "^3.3.12"
    },
    "dependencies": {
        "css-loader": "^4.3.0",
        "node-sass": "^4.14.1",
        "sass-loader": "^10.0.2"
    }
}

npm run watch修改源代码后会自动打包。
2.webpackDevServer
第一种还不够好,我们希望自动打包完后能自动打开浏览器,开启服务器。

const path = require('path')
// 引入HtmlWebpackPlugin

const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    devServer: {
        contentBase: './dist',
        open: true
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 以src下的index.html为模板构建
            template: 'src/index.html'
        }),
        // 使用此插件在我们打包前清除dist目录
        // new CleanWebpackPlugin()
    ],
    output: {
        // filename: 'bundle.js',
        // publicPath: 'http://cdn.com.cn',
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    }
}

然后再在package.json中配置命令start: “webpack-dev-server”,npm start打包即可。

devServer: {
        //  打包放置
        contentBase: './dist',
        // 自动打开
        open: true
    }

devserver配置项
3.手动创建文件

// package.json
"middleware": "node server.js"

需要用到服务器,故需安装express,中间件使用用到 webpack-dev-middleware

npm install express webpack-dev-middleware -D
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleWare = require('webpack-dev-middleware');
const config = require('./webpack.config');
// 进行代码编译,即webpack传入配置文件会返回一个编译器,编译一次重新打包一次
const complier = webpack(config);
const app = express();
app.use(webpackDevMiddleWare(complier, {
    publicPath: config.output.publicPath
}))

app.listen(3000, () => {
    console.log('server is running')
})

2-9Hot Module Replacement

// index.js
import './style.css'
var btn = document.createElement('button');
btn.innerHTML = '新增'
document.body.appendChild(btn)
btn.onclick = function () {
    var div = document.createElement('div')
    div.innerHTML = 'item'
    document.body.appendChild(div)
}

在index.js中创建元素和点击事件,点击新增生成item,引用style.css.

// style.css
div:nth-of-type(odd) {
    background: blue;
}
// webpack.config.js还是开启了devServer
const path = require('path')
// 引入HtmlWebpackPlugin

const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    devServer: {
        contentBase: './dist',
        open: true
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        },{
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader',
                'postcss-loader'
            ]
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 以src下的index.html为模板构建
            template: 'src/index.html'
        }),
        // 使用此插件在我们打包前清除dist目录
        // new CleanWebpackPlugin()
    ],
    output: {
        // filename: 'bundle.js',
        // publicPath: 'http://cdn.com.cn',
        publicPath: '/',
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    }
}

效果:在每次更改css里的代码后,浏览器就会重新刷新,我们已经点击生成的item也会丢失,我们希望只是在更改样式代码的时候浏览器只是更新样式,这就是热更新。
此时用到了HotModuleReplacementPlugin(),由于此插件是webpack内置的,需要先引入webpack,再在plugin里实例化此插件即可。(比对上面两个文件)

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const webpack = require('webpack')
module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    devServer: {
        contentBase: './dist',
        open: true,
        port: 8080,
        hot: true,
        hotOnly: true
    },
    module: {
        rules: [{
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'file-loader',
                //placehodles占位符
                options: {
                    // name: '[path][name].[ext]'
                    // outputPath: 'images/'
                }
            }
        }, {
            test: /\.scss$/,
            use: [
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                      //在引入css文件前先走下面连个loader   
                      importLoaders: 2,
                      modules: true
                  }
                },
                'sass-loader',
                'postcss-loader'
            ]
        },{
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader',
                'postcss-loader'
            ]
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 以src下的index.html为模板构建
            template: 'src/index.html'
        }),
        // 使用此插件在我们打包前清除dist目录
        // new CleanWebpackPlugin()
        new webpack.HotModuleReplacementPlugin()
    ],
    output: {
        // filename: 'bundle.js',
        // publicPath: 'http://cdn.com.cn',
        publicPath: '/',
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    }
}

Hot Module Replacement的另一种使用(热更新模块)

引出:

// src/counter.js
function counter () {
    var div = document.createElement('div');
    div.setAttribute('id', 'counter');
    div.innerHTML = 1;
    div.onclick = function () {
        div.innerHTML = parseInt(div.innerHTML, 10) + 1
    }
    document.body.appendChild(div);
}
export default counter;
//src/number.js
function number () {
    var div = document.createElement('div');
    div.setAttribute('id', 'number');
    div.innerHTML = 2000;
    document.body.appendChild(div);
}
export default number;

同时,我们在上一个webpack.config.js上暂时关闭hot,与hotOnly

 // hot: true,
        // hotOnly: true

效果是我们点击使1增加时,然后去改动number.js的2000,会自动打包,而我们的1增加后的值也会刷新重置了,而我们想要的效果是改动number.js的代码只改动number.js的。

对比:
把上面的hot和hotOnly打开,即打开热更新,在修改了number.js的2000会重新打包,但浏览器上的值没有变化(刷新会重置),这时候我们需要用代码。

// index.js
import counter from './counter'
import number from './number'
counter()
number()

if (module.hot) {
    module.hot.accept('./number', () => {
        //即number文件发生变动时重新执行一次number
        document.body.removeChild(document.getElementById('number'))
        number();
    })
}

这样的话就实现了我们的效果
其实cssloader和vue-loader等 底层也是实现了,所以不用手动实现。

2-10 ES6语法转化(Babel)

babel中文网
在这个链接里面首页的设置里面进去点击webpack,就会有配置介绍。

npm install --save-dev babel-loader @babel/core
module: {
  rules: [
    { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
  ]
}
//  index.js
const arr = [
    new Promise(() => {}),
    new Promise(() => {})
];

arr.map((item) => {
    console.log(item)
})
npm install @babel/preset-env --save-dev

只安装babel-loader不会转化代码,此loader只是打通了webpack与loader通讯而已,故还需要安装@babel/preset-env。

 rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader",
            options: {
                presets: ["@babel/preset-env"]
            }
        }

npx webpack
在这里插入图片描述
这样只翻译了一部分例如const=> var,我们还需要借助babel pollyfill工具帮助我们对变量或函数在低版本浏览器的补充
babel pollyfill

npm install --save @babel/polyfill
// index.js
import "@babel/polyfill"

const arr = [
    new Promise(() => {}),
    new Promise(() => {})
];

arr.map((item) => {
    console.log(item)
})

按需填充
上面的配置会把所有的填充上去,为了减少体积,我们可以按需填充。

 module: {
        rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader",
            options: {
                presets: [["@babel/preset-env",{
                    //  按需填充参数配置
                    useBuiltIns: 'usage'
                }]]
            }
        }

还可以配置target等属性

 rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader",
            options: {
                presets: [["@babel/preset-env",{
                    targets: {
                        chrome: "67"
                },
                    useBuiltIns: 'usage'
                }]]
            }
        }

如果打包是一个库时,需要换一种配置,使用:
transform-runtime

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
 rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader",
            options: {
                // presets: [["@babel/preset-env",{
                //     targets: {
                //         chrome: "67"
                // },
                //     useBuiltIns: 'usage'
                // }]]
                "plugins": [["@babel/plugin-transform-runtime",{
                    "corejs": false,
                    "helpers": true,
                    "regenerator": true,
                    "useESModules": false,
                }]]
            }
        },

为了减少webpack.config.js的代码,可以把babel的配置放到.babelrc上
把上面的options放到.babelrc即可

//  webpack.config.js
rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader"
        }
// .babelrc
{
    "plugins": [["@babel/plugin-transform-runtime",{
        "corejs": false,
        "helpers": true,
        "regenerator": true,
        "useESModules": false,
    }]]
}

配置 React代码的打包

babel-preset-react

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值