mini-css-extract-plugin
配合使用paths
路径是绝对路径 npm i purgecss-webpack-plugin mini-css-extract-plugin css-loader glob -D
webpack.config.js
const path = require("path");
+const glob = require("glob");
+const PurgecssPlugin = require("purgecss-webpack-plugin");
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = {
mode: "development",
entry: "./src/index.js",
module: {
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
+ {
+ test: /\.css$/,
+ include: path.resolve(__dirname, "src"),
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: MiniCssExtractPlugin.loader,
+ },
+ "css-loader",
+ ],
+ },
],
},
plugins: [
+ new MiniCssExtractPlugin({
+ filename: "[name].css",
+ }),
+ new PurgecssPlugin({
+ paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
+ })
],
};
npm i thread-loader- D
const path = require("path");
const glob = require("glob");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const DllReferencePlugin = require("webpack/lib/DllReferencePlugin.js");
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = {
mode: "development",
entry: "./src/index.js",
module: {
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
+ {
+ loader:'thread-loader',
+ options:{
+ workers:3
+ }
+ },
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
{
test: /\.css$/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
}),
new DllReferencePlugin({
manifest: require("./dist/react.manifest.json"),
}),
],
};
<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'
},
}
指纹占位符
占位符名称 | 含义 |
---|---|
ext | 资源后缀名 |
name | 文件名称 |
path | 文件的相对路径 |
folder | 文件所在的文件夹 |
hash | 每次webpack构建时生成一个唯一的hash值 |
chunkhash | 根据chunk生成hash值,来源于同一个chunk,则hash值就一样 |
contenthash | 根据内容生成hash值,文件内容相同hash值就相同 |
const path = require("path");
const glob = require("glob");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = {
mode: "production",
+ entry: {
+ main: './src/index.js',
+ vender:['lodash']
+ },
output:{
path:path.resolve(__dirname,'dist'),
+ filename:'[name].[hash].js'
},
devServer:{
hot:false
},
module: {
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
{
loader:'thread-loader',
options:{
workers:3
}
},
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
{
test: /\.css$/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
+ filename: "[name].[hash].css"
}),
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
}),
],
};
const path = require("path");
const glob = require("glob");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = {
mode: "production",
entry: {
main: './src/index.js',
vender:['lodash']
},
output:{
path:path.resolve(__dirname,'dist'),
+ filename:'[name].[chunkhash].js'
},
devServer:{
hot:false
},
module: {
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
{
loader:'thread-loader',
options:{
workers:3
}
},
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
{
test: /\.css$/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
+ filename: "[name].[chunkhash].css"
}),
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
}),
],
};
mini-css-extract-plugin
里的contenthash
值,保证即使css文件所处的模块里就算其他文件内容改变,只要css文件内容不变,那么不会重复构建const path = require("path");
const glob = require("glob");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = {
mode: "production",
entry: {
main: './src/index.js',
vender:['lodash']
},
output:{
path:path.resolve(__dirname,'dist'),
filename:'[name].[chunkhash].js'
},
devServer:{
hot:false
},
module: {
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
{
loader:'thread-loader',
options:{
workers:3
}
},
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
{
test: /\.css$/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
+ filename: "[name].[contenthash].css"
}),
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
}),
],
};
module:false
即可在production mode
下默认开启"sideEffects":["*.css"]
webpack.config.js
const path = require("path");
const glob = require("glob");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = {
+ mode: "production",
+ devtool:false,
entry: {
main: './src/index.js'
},
output:{
path:path.resolve(__dirname,'dist'),
filename:'[name].[hash].js'
},
module: {
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
{
loader:'thread-loader',
options:{
workers:3
}
},
{
loader: "babel-loader",
options: {
+ presets: [["@babel/preset-env",{"modules":false}], "@babel/preset-react"],
},
},
],
},
{
test: /\.css$/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css"
}),
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
}),
],
};
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>
index.js
import React, { Component, Suspense } from "react";
import ReactDOM from "react-dom";
import Loading from "./components/Loading";
/* function lazy(loadFunction) {
return class LazyComponent extends React.Component {
state = { Comp: null };
componentDidMount() {
loadFunction().then((result) => {
this.setState({ Comp: result.default });
});
}
render() {
let Comp = this.state.Comp;
return Comp ? <Comp {...this.props} /> : null;
}
};
} */
const AppTitle = React.lazy(() =>
import(/* webpackChunkName: "title" */ "./components/Title")
);
class App extends Component {
constructor(){
super();
this.state = {visible:false};
}
show(){
this.setState({ visible: true });
};
render() {
return (
<>
{this.state.visible && (
<Suspense fallback={<Loading />}>
<AppTitle />
</Suspense>
)}
<button onClick={this.show.bind(this)}>加载</button>
</>
);
}
}
ReactDOM.render(<App />, document.querySelector("#root"));
src\components\Loading.js
import React, { Component, Suspense } from "react";
export default (props) => {
return <p>Loading</p>;
};
src\components\Title.js
import React, { Component, Suspense } from "react";
export default props=>{
return <p>Title</p>;
}
Low
<link rel="preload" as="script" href="utils.js">
import(
`./utils.js`
/* webpackPreload: true */
/* webpackChunkName: "utils" */
)
<link rel="prefetch" href="utils.js" as="script">
button.addEventListener('click', () => {
import(
`./utils.js`
/* webpackPrefetch: true */
/* webpackChunkName: "utils" */
).then(result => {
result.default.log('hello');
})
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="prefetch" href="prefetch.js?k=1" as="script">
<link rel="prefetch" href="prefetch.js?k=2" as="script">
<link rel="prefetch" href="prefetch.js?k=3" as="script">
<link rel="prefetch" href="prefetch.js?k=4" as="script">
<link rel="prefetch" href="prefetch.js?k=5" as="script">
</head>
<body>
</body>
<link rel="preload" href="preload.js" as="script">
</html>
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
{
entry: {
page1: "./src/page1.js",
page2: "./src/page2.js",
page3: "./src/page3.js",
},
optimization: {
splitChunks: {
chunks: "all", //默认作用于异步chunk,值为all/initial/async
minSize: 0, //默认值是30kb,代码块的最小尺寸
minChunks: 1, //被多少模块共享,在分割之前模块的被引用次数
maxAsyncRequests: 3, //限制异步模块内部的并行最大请求数的,说白了你可以理解为是每个import()它里面的最大并行请求数量
maxInitialRequests: 5, //限制入口的拆分数量
name: true, //打包后的名称,默认是chunk的名字通过分隔符(默认是~)分隔开,如vendor~
automaticNameDelimiter: "~", //默认webpack将会使用入口名和代码块的名称生成命名,比如 'vendors~main.js'
cacheGroups: {
//设置缓存组用来抽取满足不同规则的chunk,下面以生成common为例
vendors: {
chunks: "all",
test: /node_modules/, //条件
priority: -10, ///优先级,一个chunk很可能满足多个缓存组,会被抽取到优先级高的缓存组中,为了能够让自定义缓存组有更高的优先级(默认0),默认缓存组的priority属性为负值.
},
default: {
chunks: "all",
minSize: 0, //最小提取字节数
minChunks: 2, //最少被几个chunk引用
priority: -20,
reuseExistingChunk: false
}
},
runtimeChunk:true
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html',
chunks:["page1"],
filename:'page1.html'
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
chunks:["page2"],
filename:'page2.html'
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
chunks:["page3"],
filename:'page3.html'
})
]
}
src\page1.js
import module1 from "./module1";
import module2 from "./module2";
import $ from "jquery";
console.log(module1, module2, $);
import(/* webpackChunkName: "asyncModule1" */ "./asyncModule1");
src\page2.js
import module1 from "./module1";
import module2 from "./module2";
import $ from "jquery";
console.log(module1, module2, $);
src\page3.js
import module1 from "./module1";
import module3 from "./module3";
import $ from "jquery";
console.log(module1, module3, $);
src\module1.js
console.log("module1");
src\module2.js
console.log("module2");
src\module3.js
console.log("module3");
src\asyncModule1.js
import _ from 'lodash';
console.log(_);
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 中
{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}]
},
npm i cache-loader -D
const loaders = ['babel-loader'];
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
'cache-loader',
...loaders
],
include: path.resolve('src')
}
]
}
}
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
//优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下 loader 只会匹配一个
oneOf: [
...,
{},
{}
]
}
]
}
}