前言
一开始接触 webpack 是因为使用 vue 的关系, 因为 Vue 的脚手架就是使用 webpack 构建的. 刚开始的时候觉得 webpack 就是为了打包单页面而生的, 后来想想, 这么好的打包方案, 只在单页面上使用是否太浪费资源了呢? 如果能在传统多页面上使用 webpack, 开始效率是否会事半功倍呢? 好在众多优秀的前端开发者已经写了许多 demo 和文章供人学习. 我也写了一个小项目, 希望对大家学习 webpack 有帮助.
好吧其实上面说的都是废话, 接下来附上项目地址和干货, 配合食用更佳.
https://github.com/BYChoo/webpack-multi-page
项目解决的问题
SPA 好复杂, 我还是喜欢传统的多页应用怎么破? 又或是, 我司项目需要后端渲染, 页面模板怎么出?
每个页面相同的 UI 布局好难维护, UI 稍微改一点就要到每个页面去改, 好麻烦还容易漏, 怎么破?
能不能整合进 ESLint 来检查语法?
能不能整合 postCSS 来加强浏览器兼容性?
我可以使用在 webpack 中使用 jQuery 吗?
我可以使用在 webpack 中使用 typescript 吗?
src 目录对应 dist 目录
当我们使用 webpack 打包多页面, 我们希望 src 目录对应打包后 dist 目录是如上图这样的, 开发根据页面模块的思路搭建开发架构, 然后经过 webpack 打包, 生成传统页面的构架.
- /**
- * 创建打包路径
- */
- const createFiles = function() {
- const usePug = require('../config').usePug;
- const useTypeScript = require('../config').useTypeScript;
- const path = require('path');
- const glob = require('glob');
- const result = [];
- const type = usePug ? 'pug' : 'html';
- const scriptType = useTypeScript ? 'ts' : 'js';
- const files = glob.sync(path.join(__dirname, `../src/views/**/*.${type}`));
- for (file of files) {
- result.push({
- name: usePug ? file.match(/\w{0,}(?=\.pug)/)[0] : file.match(/\w{0,}(?=\.HTML)/)[0],
- templatePath: file,
- jsPath: file.replace(type, scriptType),
- stylePath: file.replace(type, 'stylus')
- });
- }
- return result;
- };
利用这个方法, 我们可以获得需要打包的文件路径(方法中获取文件路径的模块也可使用 fs 模块), 根据获得打包的文件路径, 我们可以使用 **HTML-webpack-plugin** 来实现多页面打包.
由于每一个 HTML-webpack-plugin 的对象实例都只针对 / 生成一个页面, 因此, 我们做多页应用的话, 就要配置多个 HTML-webpack-plugin 的对象实例:
- const plugins = function() {
- const files = createFiles();
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- const path = require('path');
- const ExtractTextPlugin = require('extract-text-webpack-plugin');
- let htmlPlugins = [];
- let Entries = {};
- files.map(file => {
- htmlPlugins.push(
- new HtmlWebpackPlugin({
- filename: `${file.name}.html`,
- template: file.templatePath,
- chunks: [file.name]
- })
- );
- Entries[file.name] = file.jsPath;
- });
- return {
- plugins: [
- ...htmlPlugins,
- new ExtractTextPlugin({
- filename: getPath => {
- return getPath('css/[name].css');
- }
- })
- ],
- Entries
- };
- };
由于我使用了 ExtractTextPlugin, 因此这些 CSS 代码最终都会生成到所属 chunk 的目录里成为一个 CSS 文件.
模版引擎
每个页面相同的 UI 布局好难维护, UI 稍微改一点就要到每个页面去改, 好麻烦还容易漏, 怎么破?
考虑到这个问题, 项目引进并使用了 **pug** 模版引擎.
现在, 我们可以利用 pug 的特性, 创建一个共用组件:
demo.pug
p 这是一个共用组件
然后, 当你需要使用这个公用组件时可以引入进来:
include 'demo.pug'
除此之外, 你还可以使用一切 pug 特供的特性.
webpack 中配置 pug 也很简单, 先安装:
NPM i --save-dev pug pug-HTML-loader
然后将所有. HTML 后缀的改为. pug 后缀, 并且使用 pug 语法.
然后在规则中再增加一条配置
- {
- test: /\.pug$/,
- use: 'pug-html-loader'
- }
同时把 plugins 对象中的用到 index.HTML 的 HtmlWebpackPlugin 中的 template, 也要改成 index.pug.
webpack 整合 eslint
先放出配置代码:
- if (useEslint) {
- loaders.push({
- test: /\.JS$/,
- loader: 'eslint-loader',
- enforce: 'pre',
- include: [path.resolve(__dirname, 'src')],
- options: {
- formatter: require('stylish')
- }
- });
- }
通过 webpack 整合 ESLint, 我们可以保证编译生成的代码都是没有语法错误且符合编码规范的; 但在开发过程中, 等到编译的时候才察觉到问题可能也是太慢了点儿.
因此我建议可以把 ESLint 整合进编辑器或 IDE 里, 像我本人在用 vs code, 就可以使用一个名为 Eslint 的插件, 一写了有问题的代码, 就马上会标识出来.
dev 环境与 prod 环境
首先, 阅读 webpacl 项目的时候通常要先看 package.JSON 这个文件. 因为当你在命令行敲下一句命令
NPM run dev
webpack 就会找到 package.JSON 文件中的 script 属性并依次分析命令, 可见, 这句命令相应的会执行
nodemon --watch build/ --exec \"cross-env NODE_ENV=development webpack-dev-server --color --progress --config build/webpack.dev.JS\"
同样的, 当写下命令
NPM run build
script 就会执行
ross-env NODE_ENV=production webpack --config build/webpack.prod.JS
这样就能区分开发环境, 或是生产环境了.
虽然我们会为环境做区分, 但是基于不重复原则, 项目为两个环境公用的配置整合到了 (build/webpack.base.JS) 文件中. 然后利用 webpack-merge 插件将配置整合在一起
webpack 中使用 jQuery
在 webpack 中使用 **jQuery** 也很简单, 我们可以在 loaders 中增加一条配置:
- if (useJquery) {
- loaders.push({
- // 通过 require('jquery')来引入
- test: require.resolve('jquery'),
- use: [
- {
- loader: 'expose-loader',
- // 暴露出去的全局变量的名称 随便你自定义
- options: 'jQuery'
- },
- {
- // 同上
- loader: 'expose-loader',
- options: '$'
- }
- ]
- });
- }
然后当你需要在某个 JS 文件使用 jq 时, 引用暴露出来的变量名即可:
import $ from 'jQuery';
webpack 中使用 typescript
在 webpack 中使用 **jQuery** 也很简单, 我们可以在 loaders 中增加一条配置:
- if (useTs) {
- loaders.push({
- test: /\.tsx?$/,
- use: 'ts-loader',
- exclude: /node_modules/
- });
- }
然后将 JS 文件改为 ts 即可.
后话
欢迎大家提 pr, 一起构建.
来源: https://juejin.im/post/5bfe5caf6fb9a049bd420063