mini-css-extract-plugin
配合使用paths
路径是绝对路径 npm i -D purgecss-webpack-plugin mini-css-extract-plugin glob
webpack.config.js
+ const glob = require('glob');
+ const PurgecssPlugin = require('purgecss-webpack-plugin');
module.exports = {
mode: 'development',
plugins: [
+ new PurgecssPlugin({
+ paths: glob.sync(`${path.join(__dirname, 'src')}/**/*`
+ }),
],
}
plugins: [
+ new MiniCssExtractPlugin({
+ filename: '[name].css',
+ chunkFilename:'[id].css'
+ }),
{
test: /\.css/,
include: path.resolve(__dirname,'src'),
exclude: /node_modules/,
use: [{
+ loader: MiniCssExtractPlugin.loader
},'css-loader']
}
.dll
为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据const path=require('path');
const DllPlugin=require('webpack/lib/DllPlugin');
module.exports={
entry: {
react:['react','react-dom']
},// 把 React 相关模块的放到一个单独的动态链接库
output: {
path: path.resolve(__dirname,'dist'),// 输出的文件都放到 dist 目录下
filename: '[name].dll.js',//输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称
library: '_dll_[name]',//存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react
},
plugins: [
new DllPlugin({
// 动态链接库的全局变量名称,需要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态链接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist', '[name].manifest.json')
})
]
}
webpack --config webpack.dll.config.js --mode development
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin')
plugins: [
new DllReferencePlugin({
manifest:require('./dist/react.manifest.json')
})
]
webpack --config webpack.config.js --mode development
<script src="react.dll.js"></script>
<script src="bundle.js"></script>
{
test: /\.(js)$/,
use: [
{
loader:'thread-loader',
options:{
workers:3
}
},
{
loader:'babel-loader'
}
],
}
<link rel="dns-prefetch" href="http://img.zhufengpeixun.cn">
去预解析域名,以降低域名解析带来的延迟要给网站接入 CDN,需要把网页的静态资源上传到 CDN 服务上去,在服务这些静态资源的时候需要通过 CDN 服务提供的 URL 地址去访问
output: {
path: path.resolve(__dirname, 'dist'),
+ filename: '[name]_[hash:8].js',
+ publicPath: 'http://img.zhufengpeixun.cn'
},
module:false
即可在production mode
下默认开启.babelrc
"presets":[
+ ["@babel/preset-env",{"modules":false}],//转译 ES6 ES7
"@babel/preset-react"//转译JSX语法
],
functions.js
function func1(){
return 'func1';
}
function func2(){
return 'func2';
}
export {
func1,
func2
}
import {func2} from './functions';
var result2 = func2();
console.log(result2);
if(false){
console.log('false')
}
import {func2} from './functions';
func2();
var aabbcc='aabbcc';
aabbcc='eeffgg';
entry: {
index: "./src/index.js",
login: "./src/login.js"
}
hello.js
module.exports = "hello";
index.js
document.querySelector('#clickBtn').addEventListener('click',() => {
import('./hello').then(result => {
console.log(result.default);
});
});
index.html
<button id="clickBtn">点我</button>
大网站有多个页面,每个页面由于采用相同技术栈和样式代码,会包含很多公共代码,如果都包含进来会有问题
默认配置
optimization: {
splitChunks: {
chunks: "all",//默认作用于异步chunk,值为all/initial/async
minSize: 30000, //默认值是30kb,代码块的最小尺寸
minChunks: 1, //被多少模块共享,在分割之前模块的被引用次数
maxAsyncRequests: 5, //按需加载最大并行请求数量
maxInitialRequests: 3, //一个入口的最大并行请求数量
name: true, //打包后的名称,默认是chunk的名字通过分隔符(默认是~)分隔开,如vendor~
automaticNameDelimiter: '~',//默认webpack将会使用入口名和代码块的名称生成命名,比如 'vendors~main.js'
cacheGroups: { //设置缓存组用来抽取满足不同规则的chunk,下面以生成common为例
vendors: {
chunks: "initial",
test: /node_modules/,//条件
priority: -10 ///优先级,一个chunk很可能满足多个缓存组,会被抽取到优先级高的缓存组中,为了能够让自定义缓存组有更高的优先级(默认0),默认缓存组的priority属性为负值.
},
commons: {
chunks: "initial",
minSize: 0,//最小提取字节数
minChunks: 2, //最少被几个chunk引用
priority: -20,
reuseExistingChunk: true// 如果该chunk中引用了已经被抽取的chunk,直接引用该chunk,不会重复打包代码
}
}
},
}
pageA.js
import utils1 from './utils1';
import utils2 from './utils2';
import $ from 'jquery';
console.log(utils1,utils2,$);
pageB.js
import utils1 from './utils1';
import utils2 from './utils2';
import $ from 'jquery';
console.log(utils1,utils2,$);;
pageC.js
import utils3 from './utils3';
import utils1 from './utils1';
import $ from 'jquery';
console.log(utils1,utils3,$);
utils1.js
utils2.js
utils3.js
webpack.config.js
entry: {
pageA: './src/pageA',
pageB: './src/pageB',
pageC: './src/pageC'
},
output: {
path: path.resolve(__dirname,'dist'),
filename: '[name].js'
},
plugins:[
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'pageA.html',
excludeChunks: ['pageB','pageC']
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'pageB.html',
excludeChunks: ['pageA','pageC']
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'pageC.html',
excludeChunks: ['pageA','pageB']
})
]
webpack.optimize.ModuleConcatenationPlugin
插件module.exports = {
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 开启 Scope Hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
],
};
hello.js
export default 'Hello';
index.js
import str from './hello.js';
console.log(str);
输出的结果main.js
"./src/index.js":
(function(module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
var hello = ('hello');
console.log(hello);
})
函数由两个变成了一个,hello.js 中定义的内容被直接注入到了 main.js 中
--hot
const webpack = require('webpack');
module.exports = {
entry:{
main:'./src/index.js',
},
plugins: [
// 该插件的作用就是实现模块热替换,实际上当启动时带上 `--hot` 参数,会注入该插件,生成 .hot-update.json 文件。
new webpack.NamedModulesPlugin(), // 用于启动 HMR 时可以显示模块的相对路径
new webpack.HotModuleReplacementPlugin(), // Hot Module Replacement 的插件
],
devServer:{
// 告诉 DevServer 要开启模块热替换模式
hot: true,
}
};
在启动 Webpack 时带上参数 --hot 其实就是自动为你完成以上配置。
import React from 'react';
import { render } from 'react-dom';
import App from './App';
import './index.css';
render(<App/>, document.getElementById('root'));
// 只有当开启了模块热替换时 module.hot 才存在
if (module.hot) {
// accept 函数的第一个参数指出当前文件接受哪些子模块的替换,这里表示只接受 ./AppComponent 这个子模块
// 第2个参数用于在新的子模块加载完毕后需要执行的逻辑
module.hot.accept(['./App'], () => {
// 新的 AppComponent 加载成功后重新执行下组建渲染逻辑
let App=require('./App').default;
render(<App/>, document.getElementById('root'));
});
}
App.js
文件传递到index.js
文件, 直到有某层的文件接受了当前变化的模块.css
文件都会触发模块热替换的原因是style-loader
会注入用于接受 CSS 的代码