path.resolve
// 只要以/开头,就变为绝对路径
// ./和直接写效果相同
var path = require("path") //引入node的path模块path.resolve('/foo/bar', './baz') // returns '/foo/bar/baz'
path.resolve('/foo/bar', 'baz') // returns '/foo/bar/baz'
path.resolve('/foo/bar', '/baz') // returns '/baz'
path.resolve('/foo/bar', '../baz') // returns '/foo/baz'
path.resolve('home','/foo/bar', '../baz') // returns '/foo/baz'
path.resolve('home','./foo/bar', '../baz') // returns '当前工作目录/home/foo/baz'
path.resolve('home','foo/bar', '../baz') // returns '当前工作目录/home/foo/baz'
webpack.config.js
- 该文件若有更新,需要重启
- css-loader:由于import引入的样式文件会作用在全局,若想css模块化,则设置modules为true
- 默认情况下,将不接受在 HTTPS 上运行且证书无效的后端服务器
Tip
请注意,要完全启用 HMR ,需要 webpack.HotModuleReplacementPlugin。如果使用 --hot 选项启动 webpack 或 webpack-dev-server,该插件将自动添加,因此你可能不需要将其添加到 webpack.config.js 中。
加了publicPath后打包的文件在哪?如何利用cdn
/** @Author: your name* @Date: 2021-04-18 15:44:29* @LastEditTime: 2021-08-08 17:58:22* @LastEditors: Please set LastEditors* @Description: In User Settings Edit* @FilePath: \newToDoc:\hyy\webpack\webpack.config.js*/
const path = require("path");// 设置热更新
const webpack = require('webpack')const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin")// 处理vue文件
const VueLoaderPlugin = require('vue-loader/lib/plugin')module.exports = {mode: 'development', // 不设置的话是生产模式,代码会压缩成一行devtool: 'eval-source-map',// 配置sourceMap// 定位到源代码的错误行数// https://webpack.docschina.org/configuration/devtool/// source-map会生成map文件,打包后文件的最后一行会显示对应的.map文件// inline-source-map不会生成map文件,会将映射关系放在base64文件里,精确到行列(性能消耗大)// inline-cheap-source-map精确到行// inline-cheap-module-source-map检测到第三方模块里的错误// cheap-module-eval-source-map 开发环境:有提示,速度尚可,无map文件// cheap-module-source-map 有提示,速度比加eval慢,会生成.map文件entry: {// npx webpack 后面跟的入口commonjs: path.resolve(__dirname, "./src/js/commonjs.js"),es6: path.resolve(__dirname, "./src/js/es6.js"),// 完整写法 因此输出默认也是main.js(在没有配置文件名时)// 若改成test: 'xxx',则默认输出test.js// main: "./src/js/es6.js"},output: {// __dirname指的是当前文件所在文件夹的绝对路径。path: path.resolve(__dirname + "/dist"),// 输出的文件名默认是main.js// [name]是占位符写法,对应entry里的keyfilename: "js/[name].js",// 产出的文件根目录前缀,index.html引入js时会加上这个前缀// publicPath: 'http://testCdn.com'},module: {// 告诉webpack 遇到什么模块要如何处理rules: [{test: /\.vue$/,use: ["vue-loader"]},{test: /\.(png|jpe?g|gif)$/,use: {loader: 'file-loader',// v5 版本已废弃: 请考虑向 asset modules 迁移。// 用的loader要安装// https://webpack.docschina.org/loaders/file-loader/// npm install file-loader --save-dev// 那么import test from './test.jpg' test就是打包后的图片文件名(含路径)// 还可以用url-loader:用于将文件转换为 base64 URI 的 loader,打包后就不再产出图片文件了// 若图片很大且使用url-loader → base64字符串很长 → 打包后文件体积很大 → 加载时间长 这时最好用file-loader// 若图片很小且使用file-loader → 单独生成图片文件 → 多发送一次HTTP请求?不会缓存吗options: {name: '[name].[ext]',// 当打包后的文件名、扩展名和原来的一样outputPath: 'imgs/'// 若路径}// 这是对loader的配置}},{test: /\.(png|jpe?g|gif)$/,use: {loader: 'url-loader',options: {name: '[name].[ext]',outputPath: 'imgs/',limit: 20480,// 20kb 超出大小则会选用file-loader// 用一个url-loader就相当于url-loader + file-loader了}},},{test: /\.js$/,use: {loader: 'babel-loader',options: {// presets和plugins选其一// presets: [["@babel/preset-env", {// useBuiltIns: 'usage',// corejs: 3// }]],plugins: [['@babel/plugin-transform-runtime', {absuluteRuntime: false,corejs: 3,helpers: true,regenerator: true,useESMoudles: false,version: '7.0.0-beta.0'}]]}},// 排除node_modules里第三方文件的代码exclude: path.resolve(__dirname, 'node_modules')},{test: /\.css$/,// loader执行顺序:从后往前,从下往上,先css-loader再style-loader// 当css文件间有依赖时,css-loader会加以分析// style-loader会将css-loader处理后的结果,会放到html的<style></style>里// 可能会产生多个style标签use: ["style-loader", "css-loader"]},{test: /\.scss$/,use: ["style-loader",// "css-loader",// 以下importLoaders语法表示,如果引入的index.scss文件里又引入了其他.scss文件// 也要用postcss-loader、sass-loader处理它们// 在最新版本的webpack默认有此功能了// 由于import引入的样式文件会作用在全局,若想css模块化,则设置modules为true// 配置后使用:import myStyles from 'XXX'// xxx.className =`${myStyles.logo}`{loader: "css-loader",options: {importLoaders: 2,// ?modules: true,}},"postcss-loader","sass-loader"]// 顺序不可改动// 翻译后的样式代码就不再有嵌套等浏览器不能识别的语法// sass-loader 需要预先安装 Dart Sass 或 Node Sass// 我们推荐使用 Dart Sass。// npm install --save-dev postcss-loader 处理css3?// autoprefixer自动加上厂商前缀(考虑兼容问题) npm install autoprefixer -D// autoprefixer需和postcss配合使用,创建postcss.config.js配置文件},// 处理字体图标:让字体图标生效{test: /\.(eot|svg|ttf|woff)/,use: ['file-loader']},{test: /\.tpl$/,loader: 'ejs-loader'},]},plugins: [// 打包后自动在dist文件夹下生成index.html// 和module同级// 用到的loader、plugin都需要npm安装// 实例化// 会以template提供的模板为基础生成index.html,并会引入output中指定的js文件new HtmlWebpackPlugin({filename: 'index.html',template: path.resolve(__dirname, "./src/index.html"),chunks: ['commonjs', 'es6'],excludeChunks: ['node_modules']}),// 打包前清空dist目录new CleanWebpackPlugin(),new webpack.HotModuleReplacementPlugin(),new VueLoaderPlugin()],// devServer只存在于开发环境!!线上没有代理// https://webpack.docschina.org/configuration/dev-server/#root// 使用前先安装// 充当服务器的作用,启动本地端口,访问端口时会返回打包的html的内容devServer: {// 自动打开open: true,host: "localhost",port: 3333,// 接口地址是/Yixiantong开头的,则转发到xxxproxy: {'/api': {target: 'http://study.jsplusplus.com',secure: false, // 如果target是https的pathRewrite: {'^/api': ''},// 接口对源有限制changeOrigin: true}},// 开启热更新 1. 引入webpack 2. 配置plugins 3. hot设为truehot: true,}
};
postcss.config.js
- 引入autoprefixer
// 参考https://webpack.docschina.org/loaders/postcss-loader/
module.exports = {plugins: [require('autoprefixer')],
};
package.json
- 想在浏览器中看到postcss-loader + autoprefixer的效果(使用transform时,翻译后自动加上厂商前缀:
-webkit-transform: rotate(-45deg)
) - 配置项目针对的是市场份额大于1%,上两个版本的浏览器
"browserslist":["> 1%", "last 2 versions"]
- dev:启动dev server服务器
- build:相当于npx webpack
- dev server:只要修改了源代码就能看到最新的结果
- watch: 监听代码变化,那就不是运行在port了,而是要运行dist里的index.html
"scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "webpack-dev-server --config webpack.config.js","watch": "webpack --watch","build": "webpack --config webpack.config.js"},
clean-webpack-plugin插件
https://www.npmjs.com/package/clean-webpack-plugin
- cnpm install --save-dev clean-webpack-plugin
- 每次打包都能清空dist目录
请求转发
- webpack-dev-server底层使用了
http-proxy-middleware
来实现功能
https://webpack.docschina.org/configuration/dev-server/#root
不带前缀
- 将
http://localhost:3333/Yixiantong/getHomeDatas
转发到接口的域名下
import axios from 'axios'
// 正式/开发环境的接口地址不同,因此使用相对路径,而不能写死
axios.get('/Yixiantong/getHomeDatas').then((res) => {console.log(res)
})
- webpack.config.js
devServer: {// 自动打开open: true,host: "localhost",port: 3333,// 接口地址是/Yixiantong开头的,则转发到xxxproxy: {'/Yixiantong': {target: 'http://study.jsplusplus.com',// 接口对源有限制changeOrigin: true}},
}
带前缀
axios.get('/api/Yixiantong/getHomeDatas').then((res) => {console.log(res)
})
- webpack.config.js
devServer: {// 自动打开open: true,host: "localhost",port: 3333,// 接口地址是/Yixiantong开头的,则转发到xxxproxy: {'/api': {target: 'http://study.jsplusplus.com',secure: false, // 如果target是https的pathRewrite: {'^/api': ''},// 接口对源有限制changeOrigin: true}},
}
npm run dev
npm run dev
时并没有生成dist文件夹- webpack devserver会把打包生成的文件放到内存里,提高了打包效率
HMR热更新(需要实践验证各场景)
- 需要两步:配置文件 + index.js监听
- 开启热更新后,控制台会显示
[WDS] Hot Module Replacement enabled.
- 热更新,源代码修改,页面不会刷新,浏览器也不会重新下载html文件,能保留原先渲染的内容、路由、表单输入、变量等
- style-loader内置了
if(module.hot)
帮助实现了热更新,不用手动去配置
// 1.
const webpack = require('webpack')
// 2.
plugins: [new webpack.HotModuleReplacementPlugin()
],
// 3.
devServer: {hot: true,
}
- js里的热更新:
- vue-loader、react babel-preset实现了热更新
- counter.js(入口)
import number from './number'
const count = document.createElement('div')
count.setAttribute('id', 'count')
count.innerText = 1
document.body.appendChild(count)
setInterval(() => {count.innerText = +count.innerText + 1
}, 1000);number()// 4. 监听number模块的变化
if (module.hot) {console.log('module', module)// accept接受监听的范围module.hot.accept('./number', () => {console.log('【不要清空counter,且重新执行number】')const oldNumber = document.getElementById('number')document.body.removeChild(oldNumber)number()})
}
- number.js
function number() {console.log('【number里重新执行了】')const div = document.createElement('div')div.setAttribute('id', 'number')div.innerText = 100document.body.appendChild(div)
}export default number
babel
https://blog.csdn.net/weixin_43503511/article/details/118628148
- 安装babel-loader(建立起webpack和babel的桥梁) babel-core
- 配置mudule → rules
- 安装babel-preset-env(将ES5转译成ES6)
- 安装babel-polyfill(补丁)
- babel-polyfill(转换新的API以及一些定义在全局对象上的方法)打包体积增加
- core-js + regenerator 支持所有新特性→ babel-polyfill(将二者组合)
- 按需引入后,不需要在业务代码中import ‘babel-polyfill’(全局引入),需要安装core-js
- 使用babel-polyfill会污染全局,它在全局上添加新特性属性
babel-plugin-transform-runtime
,大致意思是重命名新特性,若用户也在全局上定义window.Promise则不会冲突 +cnpm i -S @babel/runtime-corejs3
,在开发库的时候才会用到- 可以将options的内容放入babelrc文件,更加清晰
- preset的执行顺序也是从下往上的
Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的
API,比如Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign、Array.from等)都不会转码。
{test: /\.js$/,use: {loader: "babel-loader",// 这里和babelrc是一样的options: {presets: [["@babel/preset-env",{useBuiltIns: 'usage',corejs: 3}]]// 告诉polyfill只处理使用到的新特性(按需使用)}},// 排除node_modules里第三方文件的代码exclude: path.resolve(__dirname, 'node_modules')
},
解析react jsx
- 安装@babel/preset-react
https://babeljs.io/docs/en/babel-preset-react#docsNav
解析vue
- 安装vue-loader vue-template-compiler
- 引入VueLoaderPlugin
const VueLoaderPlugin = require('vue-loader/lib/plugin')
rules: [{test: /\.vue$/,use: ["vue-loader"]}
]
plugins: [new VueLoaderPlugin()
],