简介
按照webpack官网的说法,webpack本质上是javascript应用程序的静态资源打包器(static module bundler),它可以将模块按照依赖和规则打包成符合生产环境部署的前端资源。webpack可以将按模块异步加载按需引用,通过loader的转换还可以将任何资源看作模块,比如css、图片、json、commonjs模块、amd模块、es6模块等。如今webpack的大版本更新到4.x了,让我们看下如何使用。
1.安装使用
新建一个文件夹,依次执行:
npm initnpm i webpack webpack-cli webpack-server -D复制代码
即可开始使用webpack。在文件夹中新建文件夹 src
、dist
和文件webpack.config.js
,其中 src
为打包的源目录用来存放我们要打包的文件,dist
为输出目录,webpack.config.js
是我们配置webpack打包相关参数的文件。
- 项目目录
- webpack.config.js
//webpack.config.jsconst path = require('path')module.exports = { // 打包模式,可选development和production mode: 'development', // 配置入口文件 entry: './src/index.js', // 配置输出文件 output: { // 输出路径 path: path.resolve(__dirname, './dist'), // 输出文件名称 filename: 'build.js' }, // 模块,可以使用各种loader,比如css转换,图片压缩等 module: {}, // 插件,用于生成模板和其它功能 plugins: [], // 可配置本地的webpack开发服务功能 devServer: {}}复制代码
编写好webpack.config.js之后就使用命令npx webpack
开始执行打包了。webpack的打包机制,只能以js文件为入口,如果你需要打包图片,css,字体,svg等资源,必须使用es6或commonjs等模块加载规范在入口文件中引入,否则是没法进行打包构建的。
- module和一些loader的使用
module可以使用loader处理引入的模块,支持的模块类型有CoffeeScript,TypeScript,ES5/6,sass,less,stylus。模块的依赖方式有:
1.ES2015 import
语句
2. CommonJS require()
语句
3. AMD define
和 require
语句
4. css/sass/less 文件中的 @import
语句
5. 样式(url(...))
或 HTML 文件(<img src=...>)
中的图片链接(image url)
下面我用一些loader来介绍module的用法,注意使用loader之前需要使用npm安装对应的loader(npm i xxx-loader -D
)
// webpack.config.jsmodule.exports = { mode: '', entry: '', output: {}, module: { rules: [ { test: /\.css$/, // 匹配css文件模块 use: ['style-loader', 'css-loader'] // 使用对应的loader处理 }, { test: /\.(png|gif|jpe?g|svg)$/, // 匹配图片文件 use: [{ loader: 'file-loader', options: { name: '[path][name].[ext]?[hash]', // 会输出类似下面这样的结果 // path/to/file.png?e43b20c069c4a01867c31e98cbce33c9 } }] }, { test: /\.(html)$/, // 用来匹配html文件模块(html需要通过插件引入?),可以将html标签中引入的图片资源进行打包 use: [{ loader: 'html-loader', options: { attrs: [': '] // 为引入图片的标签名, 为引入图片的属性名 } }] } ] }, plugins: [], devServer: {}}复制代码
通过上面例子中几个loader的使用,大致的介绍了模块的作用和用法。如果没有你需要的功能,可以去上去寻找。
另外还有一个图片打包url-loader,需要注意它和file-loader的区别。url-loader可以说是file-loader的进一步封装,可以将图片转换为base64格式内联在代码中,这样可以减少图片加载的http请求。
- plugins插件的使用
plugins也是webpack的重要功能之一,借助插件我们可以实现loader无法完成的工作。要使用插件之前,同样需要使用npm安装(npm i xxx -D
),并且在webpack.config.js中要引用该插件。下面我简单介绍几个插件的用法,想要更完整的资料可以访问。
// webpack.config.jsconst path = require('path')// 使用插件之前需要先加载对应的pluginconst CleanWebpackPlugin = require('clear-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')const CopyWebpackPlugin = require('copy-webpack-plugin')module.exports = { mode: '', entry: { a: './src/a.js', // 可以引入多个入口文件 b: './src/b.js' }, output: { path: path.resolve(__dirname + '/dist/'), filename: '[name].[hash:8].js' // 输出多个结果,文件名带hash值 }, module: {}, plugins: [ // 每次构建完成后先清理一遍dist目录 new CleanWebpackPlugin(['dist']), // 生成html文件到输入目录 new HtmlWebpackPlugin({ // 可以以src目录下的html源文件为模板 template: './src/index.html', // 在目标目录下生成目标文件 filename: './dist/index.html', chunks: ['a', 'b'] // 这个参数配合entry可以将打包的模块以的形式加载到html文件中 }), // 该插件可以将源目录中的文件直接复制到目标目录中 new CopyWebpackplugin([{ from: './src/*.css', // 选择源目录下的所有css文件 flatten: true // 选择拷贝文件还是包括文件夹,默认是false }]) ], devServer: {}}复制代码
- devServer
devServer可以在本地搭建一个webpack构建服务环境
// webpack.config.jsmodule.exports = { mode: '', entry: {}, output: {}, module: {}, plugins: [], devServer: { contentBase: '/dist', // 服务的内容目录 port: 4396, // 搭建在本地的服务的端口号 compress: true, // 服务开启gzip压缩 open: true // 自动打开本地浏览器 }}复制代码
同时将项目目录下的package.json改写一下。
// package.json"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack-dev-server", // 开启本地的webpack开发服务环境 "build": "webpack" // 执行打包}复制代码
之后我们就可以执行npm run start
、npm run webpack
开启服务,执行打包。
2.多文件入口打包
多文件打包的本质就是在入口entry添加多个打包入口,在上面介绍plugins的HtmlWebpackPlugins时就用到了两个入口。我们自然而然的想到有多少个入口文件,就在entry里面添加几个入口不就好了。这样虽然可以实现多文件打包,但是每次我们新加一个入口都要手动添加,非常麻烦。所以我们想办法匹配获取到源目录下的所有的入口文件,然后添加到entry中即可。
function getEntry () { let globPath = 'src/**/*.html' // 匹配src目录下的所有文件夹中的html文件 // (\/|\\\\) 这种写法是为了兼容 windows和 mac系统目录路径的不同写法 let pathDir = 'src(\/|\\\\)(.*?)(\/|\\\\)' // 路径为src目录下的所有文件夹 let files = glob.sync(globPath) let dirname, entries = [] for (let i = 0; i < files.length; i++) { dirname = path.dirname(files[i]) entries.push(dirname.replace(new RegExp('^' + pathDir), '$2').replace('src/', '')) } return entries}function addEntry () { let entryObj = {} getEntry().forEach(item => { entryObj[item] = resolve(__dirname, 'src', item, 'index.js') }) return entryObj}复制代码
通过上面两个方法我们就能获取到src目录下的所有入口文件。下面我们看webpack.config.js如何修改
// ...{ // entry: resolve(__dirname, "src/home/index.js") // 改为 entry: addEntry() //...}// ...getEntry().forEach(pathname => { let conf = { filename: pathname.replace('src/', '') + '.html', template: path.join(__dirname, 'src', pathname, 'index.html'), chunks: Array.call([], pathname) } webpackconfig.plugins.push(new HtmlWebpackPlugin(conf))})复制代码
这样我们就能够实现自动的匹配所有入口文件和要生成的html模板文件,同时在HtmlWebpackPlugin插件使用时,也自动添加了多个模板入口,在目标目录下生成多个html文件。
上面只是大致介绍了多入口的思路,具体代码可以看我实现的一个demo
参考文章
原文链接:
作者简介: 宫晨光,人和未来大数据前端工程师。