前言
webpack是用于现代 JavaScript 应用程序的静态模块打包工具,用以构建一个前端工程化项目,如vue-cli create-react-app等脚手架工具都是基于webpack的构建或者react前端项目工程化的最佳实践。
如果你的项目是不依赖框架(vue/react/Angular)可以尝试使用webpack来构建一个前端项目。
更多关于webpack的特性请参考官网链接:webpack
webpack 工作模式
安装依赖
如果还没有初始化就先创建一个目录 在这个目录下打开命令行输入:npm init -y
初始化项目:
npm install webpack webpack-cli -D
webpack4 以后就支持 0 配置打包(也就是不需要任何配置就可以打包出js文件) 在项目根目录下创建src目录,并在src目录传index.js文件写一个简单的js代码
const a = 'mxdraw' | |
console.log(a) | |
module.exports = a; |
直接命令行运行npx webpack
就会在根目录出现dist
目录:
这个main.js就是我们打包好的js文件。
但是在命令行会提示如下信息:
这是因为我们没有设置模式
模式:供 mode 配置选项,告知 webpack 使用相应模式的内置优化,默认值为production,另外还有development、none,他们的区别如下:
参数 | 说明 |
---|---|
development | 开发模式,打包更加快速,省了代码优化步骤 |
production | 生产模式,打包比较慢,会开启 tree-shaking和压缩代码 |
none | 不使用任何默认优化选项 |
如何设置模式呢?
首先我们需要一个webpack的配置文件webpack.config.js 将这个文件放在项目根目录下,webpack.config.js内容如下:
module.exports = { | |
mode: 'development', | |
}; |
或者通过命令行的方式设置:
webpack --mode= development
虽然webpack可以0配置的使用但是在实际开发中要满足需求还是需要一些配置
这里推荐使用webpack.config.js这种文件配置的方式可以灵活的使用node的一些特性(webpack运行在node环境)去完成一些特定需求。
这里给出webpack最基本的配置信息:
const path = require('path') | |
module.exports = { | |
mode: 'development', // 模式 | |
entry: './src/index.js', // 打包入口地址 | |
output: { | |
filename: 'bundle.js', // 输出文件名 | |
path: path.join(__dirname, 'dist') // 输出文件目录 | |
} | |
} |
Loader
loader 用于对模块的源代码进行转换。
例如我们新增一个css文件:
这里我们将webpack配置中的入口(entry)修改为一个css文件:
const path = require('path') | |
module.exports = { | |
mode: 'development', // 模式 | |
entry: './src/main.css', // 打包入口地址 | |
output: { | |
filename: 'bundle.css', // 输出文件名 | |
path: path.join(__dirname, 'dist') // 输出文件目录 | |
} | |
} |
运行命令: npx webpack
结果报错了,这是因为: webpack默认只支持处理js和json文件,其他文件类型处理不了,所以要处理其他格式的文件,我们就需要借助Loader来处理
安装 css-loader
npn install css-loader -D
配置loader
const path = require('path') | |
module.exports = { | |
mode: 'development', // 模式 | |
entry: './src/main.css', // 打包入口地址 | |
output: { | |
filename: 'bundle.css', // 输出文件名 | |
path: path.join(__dirname, 'dist') // 输出文件目录 | |
}, | |
module: { | |
rules: [ // 转换规则 | |
{ | |
test: /\.css$/, //匹配所有的 css 文件 | |
use: 'css-loader' // use: 对应的 Loader 名称 | |
} | |
] | |
} | |
} |
重新运行命令打包:npx webpack
就可以将css打包了
这里只是试验,入口文件还是改回成js文件
Loader 就是将 Webpack 无法识别的内容转换为webpack可以识别的内容。
插件(plugin)
webpack插件(plugin)与Loader这种转换类型文件不同,它可以贯穿webpack整个打包的生命周期去执行不同的任务
举个例子:
1.在src下新增index.html文件
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>ITEM</title> | |
</head> | |
<body> | |
</body> | |
</html> |
2.安装webpack插件html-webpack-plugin
npm install html-webpack-plugin -D
3.配置插件
const path = require('path') | |
const HtmlWebpackPlugin = require('html-webpack-plugin') | |
module.exports = { | |
mode: 'development', // 模式 | |
entry: './src/index.js', // 打包入口地址 | |
output: { | |
filename: 'bundle.js', // 输出文件名 | |
path: path.join(__dirname, 'dist') // 输出文件目录 | |
}, | |
module: { | |
rules: [ | |
{ | |
test: /\.css$/, //匹配所有的 css 文件 | |
use: 'css-loader' // use: 对应的 Loader 名称 | |
} | |
] | |
}, | |
plugins:[ // 配置插件 | |
new HtmlWebpackPlugin({ | |
template: './src/index.html' | |
}) | |
] | |
} |
4.运行一下npx webpack 再在dist下找到index.html 会发现打包的js文件会自动引入到html中。
也就是说这个插件在webpack打包过程中完成将index.html这个文件拷贝到dist目录并且在新增了对打包后js的文件引入这个两个不同阶段的任务。
自动清空打包目录
为了包装每次打包的目录都是干净的所以打包前需要清空一下打包目录,这里使用clean-webapck-plugin来实现
安装
npm install clean-webpack-plugin -D
配置
// ... | |
const { CleanWebpackPlugin } = require('clean-webpack-plugin') | |
module.exports = { | |
// ... | |
plugins:[ // 配置插件 | |
new HtmlWebpackPlugin({ | |
template: './src/index.html' | |
}), | |
new CleanWebpackPlugin() | |
] | |
} |
区分环境
devServer是一个http本地服务,可以在本地实时预览项目
安装
npm intall webpack-dev-server
注意:当webpack-dev-server版本version >= 4.0.0时,需要使用devServer.static进行配置,不再有devServer.contentBase配置项。
详情请参考文档DevServer | webpack 中文文档
webpack.config.js 配置
const config = { | |
// ... | |
devServer: { | |
static: path.resolve(__dirname, 'public'), // 静态文件目录 | |
compress: true, //是否启动压缩 gzip | |
port: 8080, // 端口号 | |
// open:true // 是否自动打开浏览器 | |
}, | |
// ... | |
} | |
module.exports = (env, argv) => { | |
console.log('argv.mode=',argv.mode) // 打印 mode(模式) 值 | |
// 这里可以通过不同的模式修改 config 配置 | |
return config; | |
} |
配置devServer.static的目的:webpack打包对于静态文件的处理如图片,都是直接拷贝到dist目录下,对于本地开发来讲是没有必要的,设置了static对于目录就可以直接在这个目录下读取静态文件不需要拷贝移动。
启动本地服务:
npm run dev
启动 devServer
devServer是一个http本地服务,可以在本地实时预览项目。
安装
npm intall webpack-dev-server
注意:当webpack-dev-server版本version >= 4.0.0时,需要使用devServer.static进行配置,不再有devServer.contentBase配置项。
详情请参考文档DevServer | webpack 中文文档
webpack.config.js 配置
const config = { | |
// ... | |
devServer: { | |
static: path.resolve(__dirname, 'public'), // 静态文件目录 | |
compress: true, //是否启动压缩 gzip | |
port: 8080, // 端口号 | |
// open:true // 是否自动打开浏览器 | |
}, | |
// ... | |
} | |
module.exports = (env, argv) => { | |
console.log('argv.mode=',argv.mode) // 打印 mode(模式) 值 | |
// 这里可以通过不同的模式修改 config 配置 | |
return config; | |
} |
配置devServer.static的目的:webpack打包对于静态文件的处理如图片,都是直接拷贝到dist目录下,对于本地开发来讲是没有必要的,设置了static
对于目录就可以直接在这个目录下读取静态文件不需要拷贝移动。
启动本地服务:
npm run dev
引入CSS
我们在src/index.js中引入css如下:
import './main.css'; | |
const a = 'Hello ITEM' | |
console.log(a) | |
module.exports = a; |
运行打包发现css样式不起作用是因为我们css-loader只是把css文件放在dist目录了,但是没有加载这个css,下面我们使用style-loader来完成这个工作
安装
npm install style-loader -D
配置
const config = { | |
// ... | |
module :{ | |
Rules: [ | |
{ | |
test: /\.css$/, | |
use: [‘css-loader’, ‘style-loader’] | |
} | |
] | |
} | |
} |
注意: style-loader一定要放在css-loader后面才有效 因为css-loader相当于对css是对文件源码转换,而style-loader是将加载转换后的css代码加载到页面上去
style-loader是直接在在html中新增了style标签只输出css来完成样式加载的,如果需要通过引入文件的方式加载需要mini-css--extract-plugin这个插件
npm install mini-css-extract-plugin -D
webpack.config.js配置:
// ... | |
// 引入插件 | |
const MiniCssExtractPlugin = require('mini-css-extract-plugin') | |
const config = { | |
// ... | |
module: { | |
rules: [ | |
// ... | |
{ | |
test: /\.css$/, | |
use: [ | |
'css-loader', | |
// 'style-loader', | |
MiniCssExtractPlugin.loader, // 添加 loader | |
'postcss-loader', | |
'sass-loader', | |
] | |
}, | |
] | |
}, | |
// ... | |
plugins:[ // 配置插件 | |
// ... | |
new MiniCssExtractPlugin({ // 添加插件 | |
filename: '[name].[hash:8].css' | |
}), | |
// ... | |
] | |
} | |
// ... |
CSS的兼容性
使用postcss可以自动添加css3部分属性的浏览器前缀,这样我们的css样式在大部分浏览器中都能生效
npm install postcss postcss-loader postcss-preset-env -D
webpack.config.js配置:
const config = { | |
// ... | |
module: { | |
rules: [ | |
{ | |
test: /\.css$/, //匹配所有的 css 文件 | |
use: ['style-loader','css-loader', 'postcss-loader'] | |
} | |
] | |
}, | |
// ... | |
} |
根目录创建postcss.config.js配置如下:
module.exports = { | |
plugins: [require('postcss-preset-env')] | |
} |
根目录创建 postcss-preset-env 配置文件.browserslistrc
last 2 versions | |
> 0.5% | |
IE 10 |
可根据项目需求调整浏览器兼容,详情请参考:postcss-preset-env - npm
JS 兼容性(Babel)
在开发中我们想使用最新的 Js 特性,但是有些新特性的浏览器支持并不是很好,所以 JS也需要做兼容处理,常见的就是将 ES6 语法转化为 ES5。 更多请前面官网了解:Babel 中文网 · Babel - 下一代 JavaScript 语法的编译器
安装依赖
npm install babel-loader @babel/core @babel/preset-env -D
-
babel-loader 使用 Babel 加载 ES2015+ 代码并将其转换为 ES5
-
@babel/core Babel 编译的核心包
-
@babel/preset-env Babel 编译的预设,可以理解为 Babel 插件的超集
配置Babel 预设
// webpack.config.js | |
// ... | |
const config = { | |
//... | |
module: { | |
rules: [ | |
{ | |
test: /\.js$/i, | |
use: [ | |
{ | |
loader: 'babel-loader', | |
options: { | |
presets: [ | |
'@babel/preset-env' | |
], | |
} | |
} | |
] | |
}, | |
// ... | |
] | |
}, | |
//... | |
} | |
// ... |
当然还可以指定兼容那些浏览器,如果配置在webpack.config.js会让这个配置文件显得特别臃肿,建议将babel的配置都放在根目录下的babel.config.json或者.babelrc.json或者.babelrc.js
module.exports = { | |
presets: [ | |
[ | |
"@babel/preset-env", | |
{ | |
// useBuiltIns: false 默认值,无视浏览器兼容配置,引入所有 polyfill | |
// useBuiltIns: entry 根据配置的浏览器兼容,引入浏览器不兼容的 polyfill | |
// useBuiltIns: usage 会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加 | |
useBuiltIns: "entry", | |
corejs: "3.9.1", // 是 core-js 版本号 | |
targets: { | |
chrome: "58", | |
ie: "11", | |
}, | |
}, | |
], | |
], | |
}; |
还有些预设如
@babel/preset-flow
@babel/preset-react
@babel/preset-typescript可以自己了解一下
对于还未进入 ECMA 规范中的新特性, babel也是无法处理的,必须安装对应的插件:
@babel/plugin-proposal-decorators
@babel/plugin-proposal-class-properties
npm install babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D
.babelrc.js的配置
module.exports = { | |
presets: [ | |
[ | |
"@babel/preset-env", | |
{ | |
useBuiltIns: "entry", | |
corejs: "3.9.1", | |
targets: { | |
chrome: "58", | |
ie: "11", | |
}, | |
}, | |
], | |
], | |
plugins: [ | |
["@babel/plugin-proposal-decorators", { legacy: true }], | |
["@babel/plugin-proposal-class-properties", { loose: true }], | |
] | |
}; |
webpack配置使用mxdraw库的前端项目
这里只是简单的配置了一些常见需求,更多请参考webpack基础或者官方文档webpack
项目初始化:新建一个目录, 使用npm初始化
npm init -y
webpack 安装
点击开始=》运行=》输入"cmd" 打开命令行窗口
输入:
npm install webpack webpack-cli html-webpack-plugin clean-webpack-plugin webpack-dev-server css-loader style-loader file-loader csv-loader xml-loader html-loader markdown-loader babel-core babel-loader@7 babel-preset-env babel-preset-stage-0 --save-dev
提示:
-
以上webpack对应pluginloader可以根据项目实际需求安装,这里安装了项目中可能需要的部分webpack plugin和 loader
-
如果安装了yarn 建议把npm install替换为yarn add
-
以下开发环境依赖是webpack相关的一些依赖 可根据实际项目需要进行安装
-
webpack webpack-cli 是其核心和对应的模块打包工具
-
html-webpack-plugin 将打包后的js文件引入html文件中详情请参考文档
-
clean-webpack-plugin 用以清空打包后的dist目录避免文件混乱
-
webpack-dev-server 在开发环境中提供HTTP服务进行实时预览
-
css-loader style-loader 解析引入的css文件 将解析好的css内容注入到JavaScript中因此 css-loader要在style-loader前面
-
file-loader 将引入的文件解析出路径 并将文件发送到输出目录
-
csv-loader 解析数据资源csv|tsv等格式的文件
-
xml-loader 解析数据资源xml格式的文件
-
html-loader将HTML导出为字符串 在需要时压缩字符串
-
markdown-loader 解析md格式的markdown语法的文件
-
babel-core babel-loader@7 ES6转ES5语法
-
babel-preset-env babel-preset-stage-0 告诉babel要转换的源码使用了哪些新的语法特性
安装mxdraw
npm install mxdraw
初始化目录结构
新建如下文件和目录:
mxdraw-test-h5 | |
|- package.json | |
|- /public | |
|- index.html | |
|- /src | |
|- index.js | |
|- webpack.config.js | |
|- .babelrc |
public/index.html 初始化内如如下:
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>mxdraw-Test-H5</title> | |
</head> | |
<body> | |
<div> | |
<canvas id="mxcad"></canvas> | |
</div> | |
</body> | |
<style> | |
html, body { | |
width: 100%; | |
height: 100%; | |
padding: 0; | |
margin: 0; | |
} | |
.box { | |
overflow: hidden; | |
width: 100%; | |
height: 100%; | |
} | |
</style> |
src/index.js 初始化内如如下(以下是如何使用mxdraw实现绘制线段的命令的示例代码):
import Mx from "mxdraw" | |
Mx.useCoreCode().then(()=> { | |
Mx.MxFun.setMxServer() | |
Mx.MxFun.createMxObject({ | |
canvasId: "mxcad", | |
callback(mxDraw, { canvas, canvasParent }) { | |
console.log(mxDraw,"MxDrawObject模块 控件对象") | |
console.log(canvas,"dom 元素canvas") | |
console.log(canvasParent,"dom 元素canvas父级元素") | |
} | |
}) | |
Mx.MxFun.addCommand('BR_Line', ()=> { | |
// 构建取点对象 | |
const getPoint = new Mx.MrxDbgUiPrPointClass(); | |
// 构建动态绘制对象 | |
const worldDrawComment = new Mx.McEdGetPointWorldDrawObjectClass(); | |
// 开始动态拖动 行为: 鼠标点击画布时只执行一次回调函数,后续点击无效 | |
getPoint.go((status) => { | |
if (status !== 0) { | |
return; | |
} | |
// 获取鼠标在画布上的第一个点 | |
const pt1 = getPoint.value(); | |
// 将第一个点作为起始点 | |
let lastPt = pt1.clone(); | |
// 设置动态绘制的回调函数 | |
worldDrawComment.setDraw((currentPoint, pWorldDraw) => { | |
// 绘制当前鼠标移动点到起始点的线段 | |
pWorldDraw.drawLine(currentPoint, lastPt); | |
}); | |
// 设置取点对象交互过程中的动态绘制调用对象 | |
getPoint.setUserDraw(worldDrawComment) | |
// 开启动态拖动,连续取点,直到ESC退出。 行为: 鼠标点击一下执行一次回调函数 | |
getPoint.goWhile((status) => { | |
if (status === 0) { | |
// 获取第二个点的位置 | |
const pt2 = getPoint.value(); | |
// 拿到Three的场景对象 | |
let sence = Mx.MxFun.getCurrentDraw().getScene(); | |
// 创建一条 从起始点到 当前点击位置的线段 | |
let line = Mx.MxThreeJS.createLine(lastPt, pt2, 0xffffff); | |
// 将线段添加到场景中 | |
sence.add(line); | |
// 将第二点作为起始点 | |
lastPt = pt2 | |
} | |
}); | |
}); | |
}) | |
}) | |
setTimeout(()=> { | |
Mx.MxFun.sendStringToExecute('BR_Line') | |
}, 1000) |
package.json 完整配置如下(只需在scripts中新增"build"、"webpack --config webpack.config.js"、"start"、 "webpack-dev-server"即可):
{ | |
"name": "mxdraw-test-h5", | |
"version": "1.0.0", | |
"description": "", | |
"main": "index.js", | |
"private": true, | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1", | |
"build": "webpack --config webpack.config.js", | |
"start": "webpack-dev-server" | |
}, | |
"keywords": [], | |
"author": "", | |
"license": "ISC", | |
"dependencies": { | |
"babel-core": "^6.26.3", | |
"babel-loader": "7", | |
"babel-preset-env": "^1.7.0", | |
"babel-preset-stage-0": "^6.24.1", | |
"clean-webpack-plugin": "^4.0.0", | |
"css-loader": "^6.5.1", | |
"csv-loader": "^3.0.3", | |
"file-loader": "^6.2.0", | |
"html-loader": "^3.0.1", | |
"html-webpack-plugin": "^5.5.0", | |
"markdown-loader": "^6.0.0", | |
"style-loader": "^3.3.1", | |
"webpack": "^5.65.0", | |
"webpack-cli": "^4.9.1", | |
"webpack-dev-server": "^4.7.2", | |
"xml-loader": "^1.2.1" | |
} | |
} |
webpack.config.js 配置如下:
const path = require('path'); | |
const HTMLWebpackPlugin = require('html-webpack-plugin'); | |
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); | |
const webpack = require('webpack'); | |
module.exports = { | |
mode: 'development', | |
devtool: 'inline-source-map', | |
entry: './src/index.js', | |
output: { | |
filename: '[name]-[hash:8].js', | |
path: path.resolve(__dirname, 'dist') | |
}, | |
/** | |
* 统计信息,枚举类型,可供选项: | |
* "errors-only": 只在发生错误时输出 | |
* "minimal": 只在发生错误或有新的编译时输出 | |
* "none": 没有输出 | |
* "normal": 标准输出 | |
* "verbose": 全部输出 | |
*/ | |
stats: "errors-only", | |
devServer: { | |
// 使用热加载时需要设置为 true | |
hot: true, | |
/** | |
* 下面为可选配置 | |
*/ | |
// 指定使用一个 host。默认是 localhost | |
host: 'localhost', | |
// 端口号 | |
port: 8000, | |
// 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html。通过设置为 true 进行启用 | |
historyApiFallback: { | |
disableDotRule: true | |
}, | |
// 设置接口请求代理,更多 proxy 配置请参考 https://github.com/chimurai/http-proxy-middleware#options | |
proxy: { | |
'/api/': { | |
changeOrigin: true, | |
// 目标地址 | |
target: 'http://localhost:3000', | |
// 重写路径 | |
pathRewrite: { | |
'^/api/': '/' | |
} | |
} | |
} | |
}, | |
plugins: [ | |
new HTMLWebpackPlugin({ | |
// 用于生成的HTML文档的标题 | |
title: 'Webpack 开发环境配置', | |
// webpack 生成模板的路径 | |
template: './public/index.html' | |
}), | |
// 用法:new CleanWebpackPlugin(paths [, {options}]) | |
new CleanWebpackPlugin(), | |
// 添加 NamedModulesPlugin,以便更容易查看要修补(patch)的依赖,由于设置了 mode: 'development',所以这个插件可以省略 | |
// new webpack.NamedModulesPlugin(), | |
// 进行模块热替换 | |
new webpack.HotModuleReplacementPlugin() | |
], | |
module: { | |
rules: [ | |
{ | |
test: /\.js/, | |
include: path.resolve(__dirname, 'src'), | |
loader: 'babel-loader' | |
}, | |
// 解析 css | |
{ | |
test: /\.css$/, | |
include: path.resolve(__dirname, 'src'), | |
use: [ | |
'style-loader', | |
// 还可以给 loader 添加一些配置 | |
{ | |
loader: 'css-loader', | |
options: { | |
// 开启 sourceMop | |
sourceMap: true | |
} | |
} | |
] | |
}, | |
// 解析图片资源 | |
{ | |
test: /\.(png|svg|jpg|gif)$/, | |
use: [ | |
'file-loader' | |
] | |
}, | |
// 解析 字体 | |
{ | |
test: /\.(woff|woff2|eot|ttf|otf)$/, | |
use: [ | |
'file-loader' | |
] | |
}, | |
// 解析数据资源 | |
{ | |
test: /\.(csv|tsv)$/, | |
use: [ | |
'csv-loader' | |
] | |
}, | |
// 解析数据资源 | |
{ | |
test: /\.xml$/, | |
use: [ | |
'xml-loader' | |
] | |
}, | |
// 解析 MakeDown 文件 | |
{ | |
test: /\.md$/, | |
use: [ | |
"html-loader", | |
"markdown-loader" | |
] | |
} | |
] | |
}, | |
resolve: { | |
alias: { | |
src: path.resolve(__dirname, 'src') | |
} | |
} | |
} |
.babelrc 文件配置如下:
{ | |
"presets": ["env", "stage-0"], | |
"plugins": [ | |
"transform-runtime", | |
"transform-class-properties" | |
] | |
} |
.babelrc 配置完成,此时就可以在项目中*的使用 ES6 等新增 js 语法了。
运行命令启动项目
npm run start
打开MxDraw云图服务开发包下载地址 开启MxDraw云图服务
最后打开启动的网页就能够正常显示图纸并且可以画一次线段