前言: 作为一个现代 JavaScript 应用程序的静态模块打包器, webpack 能将各种资源, 如 JS,CSS, 图片等作为模块来处理, 是当下前端工程化的一个很受欢迎的工具, webpack 目前最新的版本是 4.0, 文章将在 4.0 的基础上, 从使用者的角度, 一步步教你认识并搭建一个简单的 webpack 配置项目, 当然 webpack 的配置和使用较为丰富且复杂, 更多的内容需要参考 webpack 官网 https://webpack.js.org/concepts/
1. 两个基本的依赖:
首先 webpack 项目的两个核心基础模块是 webpack 和 webpack-cli, 这是 webpack 项目构建的前提
NPM install --save-dev webpack webpack-cli
2. 运行 webpack
默认情况下, webpack 运行构建指令默认 以项目文件夹下的 src/index.JS 作为入口文件, 运行 webpack 指令会执行默认的 webpack 配置文件.
而在一般情况下, 需要构建符合项目要求的配置文件, 可在 package.JSON 中同过 --config 配置 webpack 的执行文件(如下)
- "script":
- {
- "build": "webpack --config ./config/webpack.base.js"
- }
3. webpack 配置文件的设置
通过指定配置文件后, 接下来的工作是根据需要配置执行的配置文件
- // webpack.base.JS
- module.exports = {
- }
3.1 入口文件
指定项目的入口文件
- module.exports = {
- entry: "./****", // 指定入口文件
- }
3.1 出口文件
- module.exports = {
- entry: "./****", // 指定入口文件
- output: {
- path: path.resolve(__dirname, ....),// 输出路径, 一般为绝对路径
- filename: '****', // 输出文件名 [hash]可以用来每次以 hash 值的区别生成文件
- publicPath: 'static', // 输出解析文件的目录, url 相对于 html 页面
- },
- chunkFilename: '***'
- }
注意:
// publicPath 的解释
比如 publicPath 设置为 static 之后, HTML 页面中引用的 url 会自动加上 static
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- test
- </title>
- </head>
- <body>
- <script type="text/javascript" src="static/bundle.67c249f5bcf3681ab97e.js">
- </script>
- </body>
- </HTML>
tips: 如何理解 chunkFileName:
chunkname 是未被列入 entry 中, 却有需要被打包出来的文件命名配置, 例如, 某些公共模块需要单独的抽离出来, 这些公共模块就可以用 chunkname 来命名
可以见下面的代码分离部分
3.2 配置多个入口文件
- {
- entry: {
- App: './src/app.js',
- search: './src/search.js'
- },
- output: {
- filename: '[name].js',
- path: __dirname + '/dist'
- }
- }
- // 写入到硬盘:./dist/App.JS, ./dist/search.JS
- 3.3 clean-webpack-plugin
不断运行 webpack 的指令, 每次都会生成不同的不同 hash 值的 JS 脚本, 因此, 我们需要一个插件, 每次构建项目之前, 将原先的构建完成的文件夹删除, 首选 clean-webpack-plugin 的插件 配置相关如下
- const CleanWebpackPlugin = require('clean-webpack-plugin');
- module.exports = {
- plugins: [
- new CleanWebpackPlugin(['dist'], {
- {
- root: '', // 删除文件夹的根路径
- verbose: true, // 是否打开日志
- }
- }) // 第一个参数为删除的文件夹数组
- ]
- }
相关参数配置 https://www.npmjs.com/package/clean-webpack-plugin
3.4 HTML-webpack-plugin
webpack 构建项目时, 通过指定的入口文件, 会将所有的 JS CSS 等以依赖模块的形式打包成一个或多个的脚本文件, 通常情况下, 脚本文件会附属于 HTML 文件运行, 这时候需要将 打包好的脚本文件, 注入到 HTML 中, HTML-webpack-plugin 插件的目的是, 以一个 HTML 为模板, 将打包好的脚本注入到模板中, 相关的配置如下
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- new HtmlWebpackPlugin() // 不带任何配置时, 默认会以一个内置普通的 HTML 作为模板 HTML
- new HtmlWebpackPlugin({
- title: 'title', // 给模板中的 HTML 注入标题, 需要在模板的 HTML 中指明配置, <%= htmlWebpackPlugin.options.title %>
- filename: '', // 指定转换后的 HTML 文件名
- template: './',// 模板文件的路径
- chunk: ['main']// chunk 指定了该模板导入的模块, 在多页面的配置中, 可以在该属性中配置多个入口中的一个或者多个脚本文件
- })
4. mode 模式
所谓模式, webpack4.0 默认的模式是'production', 可以通过 mode 来更改模式为'development'
- module.exports = {
- mode: 'development' // 会将 process.env.NODE_ENV === 'development'
- mode: 'production' // 会将 process.env.NODE_ENV === 'production'
- }
- NPM i --save-dev webpack-dev-server
- // package.JSON
- {
- "name": "development",
- "version": "1.0.0",
- "description": "",
- "main": "webpack.config.js",
- "scripts": {
- "dev": "webpack-dev-server --open", // webpack-dev-server 启动
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- }
- webpack.dev.JS
- const merge = require('webpack-merge')
- module.exports = merge(base, {
- devtool: "cheap-module-eval-source-map"
- devServer: {
- port: 8088,
- compress: true,
- ...
- }
- })
- proxy: {
- '/api': {
- target: "http://localhost:3000", // 将 URL 中带有 /API 的请求代理到本地的 3000 端口的服务上
- pathRewrite: { '^/api': '' }, // 把 URL 中 path 部分的 `api` 移除掉
- },
- }...
- module.exports = {
- module: {
- rules: [
- {
- test: /\.(CSS|SCSS)$/,
- use: [
- process.env.NODE ? 'style-loader' : MiniCssExtractPlugin.loader,
- 'css-loader',
- 'sass-loader'
- ]
- }
- ]
- }
- }
- module.exports = {
- rules: [
- {
- test: /\.JS$/,
- exclude: /node_modules/,
- use: {
- loader: 'babel-loader',
- options: {
- presets: ['@babel/preset-env'],
- }
- }
- }
- ]
- }
- module.exports = {
- entry: ['babel-polyfill', './src/main.js'],
- ...
- }
- main.f66bf9d8d1fd5b0f62ae.CSS 88 bytes 0 [emitted] main
- bundle.f66bf9d8d1fd5b0f62ae.JS 66.6 KiB 0 [emitted] main
- main.f66bf9d8d1fd5b0f62ae.CSS.map 194 bytes 0 [emitted] main
- bundle.f66bf9d8d1fd5b0f62ae.JS.map 219 KiB 0 [emitted] main
- main.0c090c129f1d9d4804b0.CSS 88 bytes 0 [emitted] main
- bundle.0c090c129f1d9d4804b0.JS 154 KiB 0 [emitted] main
- main.0c090c129f1d9d4804b0.CSS.map 194 bytes 0 [emitted] main
- bundle.0c090c129f1d9d4804b0.JS.map 219 KiB 0 [emitted] main
- tips:
- NPM install --save-dev @babel/plugin-transform-runtime
- NPM install --save @babel/runtime
- {
- test: /\.JS$/,
- exclude: /node_modules/,
- use: {
- loader: 'babel-loader',
- options: {
- presets: ['@babel/preset-env'],
- plugins: ['@babel/plugin-transform-runtime']
- }
- }
- }
- const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
- module.exports = {
- //...
- optimization: {
- minimizer: [
- new UglifyJsPlugin()
- ]
- }
- }
- 7.2 DefinePlugin
- module.exports = {
- // ...
- plugins: [
- new webpack.DefinePlugin({
- PRODUCTION: JSON.stringify(true), // const PRODUCTION = true
- VERSION: JSON.stringify('5fa3b9'), // const VERSION = '5fa3b9'
- BROWSER_SUPPORTS_HTML5: true, // const BROWSER_SUPPORTS_HTML5 = 'true'
- TWO: '1+1', // const TWO = 1 + 1,
- CONSTANTS: {
- APP_VERSION: JSON.stringify('1.1.2') // const CONSTANTS = { APP_VERSION: '1.1.2' }
- }
- }),
- ],
- }...
- console.log("Running App version" + VERSION);
- if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");
- 7.3 copy-webpack-plugin
- const CopyWebpackPlugin = require('copy-webpack-plugin')
- module.exports = {
- // ...
- plugins: [
- new CopyWebpackPlugin([
- { from: 'src/file.txt', to: 'build/file.txt', }, // 顾名思义, from 配置来源, to 配置目标路径
- { from: 'src/*.ico', to: 'build/*.ico' }, // 配置项可以使用 glob
- // 可以配置很多项复制规则
- ]),
- ],
- }...
- 7.4 extract-text-webpack-plugin
- const MiniCssExtractPlugin = require('mini-css-extract-plugin')
- module.exports = {
- plugins: [
- new MiniCssExtractPlugin({
- // Options similar to the same options in webpackOptions.output
- // both options are optional
- filename: "[name].[contenthash].css",
- chunkFilename: "[id].css"
- })
- ],
- module: {
- rules: [{
- test: /\.(CSS|SCSS)$/,
- include: [path.resolve(__dirname, '../src')],
- use: [
- MiniCssExtractPlugin.loader,
- 'css-loader'
- ]
- }, ]
- }
- }
- module.exports = {
- // ...
- plugins: [
- new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
- ]
- }
- module.exports = {
- entry: {
- vendor: ["react", "lodash", "angular", ...], // 指定公共使用的第三方类库
- },
- optimization: {
- splitChunks: {
- cacheGroups: {
- vendor: {
- chunks: "initial",
- test: "vendor",
- name: "vendor", // 使用 vendor 入口作为公共部分
- enforce: true,
- },
- },
- },
- },
- // ... 其他配置
- }
- // 或者
- module.exports = {
- optimization: {
- splitChunks: {
- cacheGroups: {
- vendor: {
- test: /react|angluar|lodash/, // 直接使用 test 来做路径匹配
- chunks: "initial",
- name: "vendor",
- enforce: true,
- },
- },
- },
- },
- }
- // 或者
- module.exports = {
- optimization: {
- splitChunks: {
- cacheGroups: {
- vendor: {
- chunks: "initial",
- test: path.resolve(__dirname, "node_modules") // 路径在 node_modules 目录下的都作为公共部分
- name: "vendor", // 使用 vendor 入口作为公共部分
- enforce: true,
- },
- },
- },
- },
- }...
- module.exports = {
- output: {
- path: path.resolve(__dirname, '../dist'),
- filename: 'bundle.[hash].js',
- chunkFilename: 'vendor.[chunkhash].js'
- },
- }
- resolve
- resolve.alias
- module.exports = {
- //...
- resolve: {
- alias: {
- Util: path.resolve(__dirname, 'src/util/'),
- }
- }
- };
- import util from './src/util/sss'
- resolve.extensions
- resolve: {
- extensions: [".js", ".vue"],
- },
来源: https://www.cnblogs.com/kidflash/p/9855204.html