webpackInit

Config

/** https://liuhongwei3.github.io Inc.
* Name: webpack.config.js.js
* Date: 2020/5/1 20:59
* Author: Tadm
* Copyright (c) 2020 All Rights Reserved.
*/

// Use commonJs
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

// 设置 nodejs 环境变量
// process.env.NODE_ENV = 'development';

// loader mixin
const commonCssLoader = [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
// CSS to commonJs js
'css-loader',
// 'postcss-loader',
// package.json 配置 browserslist,加载 CSS 兼容样式
{
loader: "postcss-loader",
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
];

module.exports = {
// 单入口 --- 单页面
// 打包形成一个 chunk
entry: './src/index.js',
// --------------------------------------------------
// 打包形成一个 chunk ,不常用
// 使得 HTML 可以使用 HMR
// entry: ['./src/index.js','./src/index.html'],
// --------------------------------------------------
// 多入口 --- 多页面
// 打包生成多个 chunk
// entry: {
// index: './src/index.js',
// test: './src/test.js'
// },
// --------------------------------------------------
// 此时打包形成两个 chunk,index 包含 index and test
// entry: {
// index: ['./src/index.js','./src/test.js'],
// test: './src/test.js'
// },
// --------------------------------------------------
output: {
filename: "main.[contenthash:10].js",
path: path.resolve(__dirname, 'dist'),
// 引入资源的公共路径前缀
// publicPath: "/",
// 重命名非入口 chunk name
// chunkFilename: "[name]_chunk.js"
},
// --------------------------------------------------
// 将 node_modules 单独打包为一个 chunk 输出
// 自动分析多入口,提取公共文件
optimization: {
splitChunks: {
chunks: "all",
// >= 30kb 才分割
minSize: 30*1024,
}
},
// --------------------------------------------------
// mode -- default: production
mode: "development",
// 生产模式,自动压缩 JS 等
// mode: 'production',
// --------------------------------------------------
// externals: {
// // 可以拒绝 webpack 打包 jquery 而是通过 cdn 导入
// jquery: 'jQuery'
// },
// --------------------------------------------------
resolve: {
// 设置路径别名
alias: {
$css: path.resolve(__dirname,'src/css')
},
// 设置省略文件路径后缀名,
extensions: ['js','json','vue'],
// 设置解析模块目录
modules: [path.resolve(__dirname,'./node_modules'),'node_modules']
},
// --------------------------------------------------
devServer: {
// 运行文件目录
contentBase: path.resolve(__dirname, 'dist'),
// 监视 contentBase 下的所有文件,变化则 reload
watchContentBase: true,
watchOptions:{
ignored: /node_modules/
},
// open gzip
compress: true,
port: 8080,
open: true,
// open HMR(hot module replacement)
// CSS/less...样式文件 -- 默认可直接使用 HMR (style-loader 实现)
// JS -- 默认不可直接使用 -- 修改 JS 使其支持 -- 只支持非入口 JS 文件
// HTML -- 默认不可直接使用 -- 可将 html 添加到 entry
hot: true,
// source-map
// [inline-|hidden-|eval-][noresources-][cheap-[module-]]source-map
// development -- eval-source-map
// production -- source-map
// devtool: 'eval-source-map'
// -----------------------------
// clientLogLevel: 'none',
// quiet: true,
// // 报错不全屏显示
// overlay: false,
// -----------------------------
// 解决开发环境时跨域问题
// proxy: {
// // 接收到 /api/xxx 请求时将其转发至 localhost:3000
// '/api':{
// target: 'http:localhost:3000,',
// // 请求路径重写
// pathRewrite: {
// '^api': ''
// }
// }
// }
},
// --------------------------------------------------
// More
module: {
rules: [
// {
// oneOf: [
// xxx
// ]
// }
{
test: /\.css$/,
// handle loader: right to left
use: [
// handle before js and create style tag,put it in head tag
// 'style-loader',
// 替代 style-loader 将 css 从 js 中提取出来
// MiniCssExtractPlugin.loader,
...commonCssLoader
],
},
{
test: /\.less$/,
use: [
// 'style-loader',
// MiniCssExtractPlugin.loader,
...commonCssLoader,
'less-loader'
]
},
{
test: /\.jpg|png$/,
// use: ['file-loader']
loader: 'url-loader',
options: {
limit: 8 * 1024,
// url-loader 默认使用 es6 模块解析,而 html-loader 是使用 commonJs,则可关闭 es6 模块化
esModule: false,
name: '[hash:10].[ext]',
outputPath: 'imgs'
}
},
{
// 处理 html 文件中的 img 标签图片
test: /\.html$/,
// 引入 img ,接着由 url-loader 处理
loader: 'html-loader'
},
{
// JS 语法检查 eslint-loader eslint eslint-plugin-import eslint-config-airbnb-base
// package.json -- eslintConfig
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname,'src'),
// 指定 loader 运行顺序(优先)
enforce: "pre",
loader: 'eslint-loader',
options: {
// 自动修复检查出的错误
fix: true
}
},
{
// JS 兼容性 -- babel-loader @babel/core @babel/preset-env
// @babel/preset-env 只能处理基本的 (let/const/箭头函数...)
// @babel/polyfill 全部处理 (promise...) -- 但是会引入大量数据导致打包体积增大
// core-js 按需加载
test: /\.js$/,
exclude: /node_modules/,
// 开启多进程打包,但是该进程启动时间为约 600ms ,各有利弊
use: [
// 'thread-loader',
// {
// loader: "babel-loader",
// ...
// }
// -----------------------
// loader: 'thread-loader',
// options:{
// workers: 2
// }
],
loader: 'babel-loader',
options: {
presets: [
// '@babel/preset-env'
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {
version: 3
},
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
// open cache,再次构建时可以读取缓存
cacheDirectory: true
}
}
],
},
plugins: [
new CleanWebpackPlugin(),
// 处理 html 文件
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩 html
minify: {
// 去掉空格和注释
collapseWhitespace: true,
removeComments: true
}
}),
// 处理 CSS 将其从 JS 中单独提取出来
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:10].css'
}),
// 压缩 CSS
new OptimizeCssAssetsWebpackPlugin(),
// PWA
// new WorkboxWebpackPlugin.GenerateSW({
// // 快速启动 service-worker 并删掉旧的
// clientsClaim: true,
// skipWaiting: true
// // 还需要在入口文件中进行配置
// })
]
};

/*
tree shaking --- 去除无用代码
使用 ES6 模块化,开启 production
package.json -- "sideEffects": false/[*.css, *.less]
*/
//	package.json
{
"name": "first",
"version": "1.0.0",
"description": "webpack first usage",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server"
},
"keywords": [
"webpack"
],
"author": "tadm",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.9.6",
"@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.9.6",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^3.0.0",
"core-js": "^3.6.5",
"css-loader": "^3.5.3",
"eslint-config-airbnb-base": "^14.1.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.2.1",
"thread-loader": "^2.1.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3",
"workbox-webpack-plugin": "^5.1.3"
},
"dependencies": {
"autoprefixer": "latest",
"core-js": "^3.6.5",
"eslint": "^6.8.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-import": "^2.20.2",
"file-loader": "^6.0.0",
"html-loader": "^1.1.0",
"html-webpack-plugin": "^4.3.0",
"less-loader": "^6.0.0",
"precss": "^4.0.0",
"url-loader": "^4.1.0",
"express": "latest"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.5%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
}
}

Entry

import 'core-js/modules/es.object.to-string';
import 'core-js/modules/es.promise';
import 'core-js/modules/web.timers';


/** https://liuhongwei3.github.io Inc.
* Name: index.js
* Date: 2020/5/1 20:46
* Author: Tadm
* Copyright (c) 2020 All Rights Reserved.
*/

import data from './data/data.json'; // default can handle .js/.json, but handle .css/jpg and more is need loader
// --------------------------------------------

import './CSS/index.css';
import './CSS/index.less'; // --------------------------------------------
// import '@babel/polyfill';

function add(x, y) {
return x + y;
}

console.log(add(2, 4));
console.log(data);

const addEs = function addEs(x, y) {
return x + y;
};

console.log(addEs(6, 6));

new Promise(((resolve) => {
setTimeout(() => {
console.log('this is a setTimeout');
resolve(6);
}, 1000);
})).then((x) => {
console.log('this is then');
console.log(x);
}).catch(() => {
console.log('this is catch');
});
// --------------------------------------------
// if(module.hot){
// module.hot.accept('./xxx.js',function () {
// // 如果监听到 xxx.js 发生变化则会执行此回调函数
// xxx();
// })
// }
// --------------------------------------------
function sum(...args) {
return args.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
}

console.log(sum(1, 2, 3, 4, 5));
// --------------------------------------------
// 可以使得 xxx.js 单独打包
// import(/* webpackChunkName: 'xxx' */'./xxx.js')
// .then(({mul, count}) => {
// console.log(mul(2, 3));
// console.log(count(1, 2));
// })
// .catch(() => {
// console.log('some errors~')
// });

// 将上方代码放入异步回调函数中即可实现懒加载
// import { mul } from './test';

document.getElementById('btn').onclick = function () {
// 懒加载~:当文件需要使用时才加载~
// 预加载 prefetch:会在使用之前,提前加载js文件
// 正常加载可以认为是并行加载(同一时间加载多个文件)
// 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test.js').then(({mul}) => {
console.log(mul(4, 5));
});
};

// 注册 service-worker
// 注意:其需要运行在服务器上,serve -s dist
// if ('serviceWorker' in navigator) {
// window.addEventListener('load', () => {
// navigator.serviceWorker.register('/service-worker.js')
// .then(() => {
// console.log('service-worker register success');
// })
// .catch(() => {
// console.log('service-worker register failed');
// })
// })
// }
Author: 𝓣𝓪𝓭𝓶
Link: https://liuhongwei3.github.io/2020/05/06/webpackInit/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.