经过三个章节的学习,你已经学会搭建了一个基于webpack4的react脚手架。如果要更改配置,比如,你希望把编译后的js文件和css文件等单独放dist下的static目录下,你想想,是不是有点麻烦。你要去浏览webpack的配置文件,找到哪些配置项,然后去更改它,我们希望有个参数配置文件,只要更改参数配置,而无需更改webpack的配置文件。

1 添加参数配置文件
(1)在根目录创建config文件夹,在config文件夹内新建一个index.js文件,文件内容如下:
    'use strict'

    const path = require('path')

    module.exports = {
dev: {
assetsSubDirectory: 'static',
assetsPublicPath: '/',
},
build: {
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
}
}

我们定义了一部分配置参数,顾名思义,dev属性下的参数配置是针对开发环境,build属性下的参数配置是针对生产环境的。其中,assetsRoot是编译后的文件存放根路径,assetsSubDirectory是资源文件编译后存放的文件夹名称,assetsPublicPath是公共的路径。

(2)修改webpack.base.conf.js,如下
    const path = require('path');
const config=require('../config');
const APP_PATH = path.resolve(__dirname, '../app'); module.exports = {
entry: {
app: './app/index.js',
framework: ['react', 'react-dom'],
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
module: {
rules: [
{
test: /\.js?$/,
use: "babel-loader",
include: APP_PATH
}
]
}
};

注意:我们在webpack.base.conf.js内配置了filename,那么dev环境下默认使用该配置,可以删除webpack.dev.conf.js内关于output的配置。

(3)路径生成方法:

路径的配置需要由assetsPublicPath和assetsSubDirectory以及具体的子路径组成,我们写一个公共的方法来生成路径。无论是开发环境还是生产环境,我们都可以复用该方法。我们在build文件夹下建立一个utils.js文件。内容如下:

    const path = require('path')
const config = require('../config') exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory return path.posix.join(assetsSubDirectory, _path)
}
(4)修改webpack.prod.conf.js

在webpack.prod.conf.js页面头部引入

    const config=require('../config');
const utils=require('./utils');

修改output属性的内容

     output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash:16].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},

修改plugins内的相关配置:

    new CleanWebpackPlugin([config.build.assetsRoot], { allowExternal: true }),

    //导出css
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[hash].css'),
chunkFilename: utils.assetsPath('css/[id].[hash].css'),
}),
(5)执行编译命令查看
npm run build

查看编译后的文件是否放在static目录下了。你可以修改参数配置文件,然后试试看吧。

2 更多的配置化
 
接下去我们会把更多的参数和变量进行配置化。
(1)index.html HTML模板的位置

在config.js文件的dev和build参数下都配置index属性:

index: path.resolve(__dirname, '../public/index.html'),

修改HtmlWebpackPlugin内template的值:
webpack.prod.conf.js的相关修改:

     new HtmlWebpackPlugin({
template: config.build.index,
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
}),

webpack.dev.conf.js的相关修改:

    new HtmlWebpackPlugin({
template: config.dev.index,
inject: true
}),
(2)增加devServer 的配置

dev环境下,启动的端口号,代理相关,以及是否自动打开浏览器等等推荐可以放在参数配置文件内。
在config.js文件内增加相关配置参数:

    proxyTable: {},
host: 'localhost',
port: ,
autoOpenBrowser: true,

修改webpack.dev.conf.js内的相关配置:

     devServer: {
host: config.dev.host,
port: config.dev.port,
contentBase: path.join(__dirname, '../public'),
compress: true,
historyApiFallback: true,
hot: true,
https: false,
noInfo: true,
open: config.dev.autoOpenBrowser,
proxy: config.dev.proxyTable,
}
更多的css loader加载器
 
我们在loader中配置了less加载器,如果我们要支持其他呢,比如sass,scss等等,显然,我们需要在rules数组增加配置。其实,这里可以写成公共的生成方法。并且我们把部分参数变成可配置。比如:是否开启cssModule等。
(1)前期准备,增加部分参数配置

修改config.js内的配置:

    const path = require('path')

    module.exports = {
base: {
// 是否开启cssModule
cssModule: true,
// cssModule排除的目录, 其他css库可以放这里
cssModuleExcludePath: /public/
},
dev: {
assetsSubDirectory: 'static',
assetsPublicPath: '/', index: path.resolve(__dirname, '../public/index.html'), proxyTable: {}, host: 'localhost',
port: ,
autoOpenBrowser: true,
// 是否生成sourceMap
cssSourceMap: true, },
build: {
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/', index: path.resolve(__dirname, '../public/index.html'), // 是否生成sourceMap
productionSourceMap: true,
}
}
(2) 在utils.js内增加cssLoaders和styleLoaders方法:
    exports.cssLoaders = function (options) {
options = options || {} let cssLoader = {
loader: 'css-loader',
options: {
importLoaders: ,
sourceMap: options.sourceMap
}
}
if (options.cssModule) {
cssLoader.options.modules = true;
cssLoader.options.localIdentName = '[local]__[hash:7]';
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
function generateLoaders(loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
} if (options.extract) {
return [MiniCssExtractPlugin.loader].concat(loaders)
} else {
return ['style-loader'].concat(loaders)
}
} return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less', { javascriptEnabled: true, indentedSyntax: true }),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
} exports.styleLoaders = function (options) {
let output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
let loaderObj = {
test: new RegExp('\\.' + extension + '$'),
use: loader,
}
if (options.cssModule) {
loaderObj.exclude = options.cssModuleExcludePath;
}
output.push(loaderObj)
} if (options.cssModule) {
options.cssModule = false
const cssModuleLoaders = exports.cssLoaders(options)
for (const extension in cssModuleLoaders) {
const cssModuleLoader = cssModuleLoaders[extension]
let cssModuleLoaderObj = {
test: new RegExp('\\.' + extension + '$'),
use: cssModuleLoader,
}
cssModuleLoaderObj.include = options.cssModuleExcludePath;
output.push(cssModuleLoaderObj)
}
}
return output
}
(3) 在webpack.prod.conf.js内使用

确认是否引入了utils,如果没有引入,在页面上方增加代码:

const utils=require('./utils');

修改 module内的rules属性:

    rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true,
cssModule:config.base.cssModule,
cssModuleExcludePath:config.base.cssModuleExcludePath
})

执行编译查看:

npm run build
(4) 在webpack.dev.conf.js内使用

确认是否引入了utils,如果没有引入,在页面上方增加代码:

const utils=require('./utils');

修改 module内的rules属性:

     rules: utils.styleLoaders({
sourceMap: config.dev.cssSourceMap,
usePostCSS: true,
cssModule:config.base.cssModule,
cssModuleExcludePath:config.base.cssModuleExcludePath
})

执行dev命令试试看

npm run dev

下一节会对 如果对编译后的文件进行gzip压缩,如何让开发环境的控制台输出更加高逼格,如何更好的对编译后的文件进行bundle分析等问题展开讨论。

【webpack系列】从零搭建 webpack4+react 脚手架(四)的更多相关文章

  1. 【webpack系列】从零搭建 webpack4+react 脚手架(一)

    搭建一个React工程的方式有很多,官方也有自己的脚手架,如果你和我一样,喜欢刨根究底,从零开始自己一行一行代码创建一个React脚手架项目,那你就来对地方了.本教程是针对React新手,以及对web ...

  2. 【webpack系列】从零搭建 webpack4+react 脚手架(三)

    本章节,我们对如何在脚手架中引入CSS,如何压缩CSS,如何使用CSS Modules,如何使用less,如何使用postcss等问题进行展开学习. 1 支持css (1)在app目录,新建一个css ...

  3. 【webpack系列】从零搭建 webpack4+react 脚手架(二)

    html文件如何也同步到dist目录?bundle.js文件修改了,万一被浏览器缓存了怎么办?如何为导出的文件加md5?如何把js引用自动添加到html?非业务代码和业务代码如何分开打包?如何搭建开发 ...

  4. 【webpack系列】从零搭建 webpack4+react 脚手架(五)

    本章节,我们一起来探讨以下问题:如何对编译后的文件进行gzip压缩,如何让开发环境的控制台输出更加高逼格,如何更好的对编译后的文件进行bundle分析等. 1 gzip压缩 如果你想节省带宽提高网站速 ...

  5. 从零搭建Spring Boot脚手架(1):开篇以及技术选型

    1. 前言 目前Spring Boot已经成为主流的Java Web开发框架,熟练掌握Spring Boot并能够根据业务来定制Spring Boot成为一个Java开发者的必备技巧,但是总是零零碎碎 ...

  6. 初探webpack之从零搭建Vue开发环境

    初探webpack之搭建Vue开发环境 平时我们可以用vue-cli很方便地搭建Vue的开发环境,vue-cli确实是个好东西,让我们不需要关心webpack等一些繁杂的配置,然后直接开始写业务代码, ...

  7. 从零搭建Spring Boot脚手架(2):增加通用的功能

    1. 前言 今天开始搭建我们的kono Spring Boot脚手架,首先会集成Spring MVC并进行定制化以满足日常开发的需要,我们先做一些刚性的需求定制,后续再补充细节.如果你看了本文有什么问 ...

  8. 从零搭建Spring Boot脚手架(3):集成mybatis

    1. 前言 今天继续搭建我们的kono Spring Boot脚手架,上一文集成了一些基础的功能,比如统一返回体.统一异常处理.快速类型转换.参数校验等常用必备功能,并编写了一些单元测试进行验证,今天 ...

  9. 从零搭建Spring Boot脚手架(4):手写Mybatis通用Mapper

    1. 前言 今天继续搭建我们的kono Spring Boot脚手架,上一文把国内最流行的ORM框架Mybatis也集成了进去.但是很多时候我们希望有一些开箱即用的通用Mapper来简化我们的开发.我 ...

随机推荐

  1. php中的md5()的安全问题

    汇总下php中md5()的安全问题 安全问题1: 1.x=任意字符串  md5('x')=0e*** 2.y=任意字符串  md5('y')=0e*** 如果x==y,php会返回true,在有些时候 ...

  2. ubuntu18.04 使用管理员权限

    最近在ubuntu系统安装koa脚手架koa-generator初始化项目,报错提示要使用管理员权限执行命令. 正常情况下使用 sudo su 命令即可进入管理员权限,使用 su [ 用户名 ] 退出 ...

  3. 限流redis+lua

    限流==保险丝策略,可借助框架如spring cloud中Hystrix组件实现.今天介绍使用guava RateLimiter 类实现接口限流. 比如12306抢票: https://blog.cs ...

  4. window.location的方法属性详解

    示例URL:http://b.a.com:88/index.php?name=kang&when=2011#first 属性 含义 值 protocol: 协议 "http:&quo ...

  5. VLAN原理解释

    转发至http://network.51cto.com/art/201409/450885.htm 为什么需要VLAN 1. 什么是VLAN? VLAN(Virtual LAN),翻译成中文是“虚拟局 ...

  6. Redis的安装与常用配置说明

    1.redis安装步骤 1).下载,上传到Linux服务器,并解压 2).预编译(实际上是检查编译环境的过程) 进入目录:   cd /opt/soft/redis-3.2.9/deps/jemall ...

  7. PowerPoint 中插入 Latex 公式

    做 PPT 用 Latex Beamer 毕竟还是太麻烦,Beamer 毕竟还是更适合学术性的,各种定义各种公式的那种,遇到要画各种图,插入各种图片,进行错综复杂的排版就比较棘手了. 最终还是 Pow ...

  8. 内网环境上部署k8s+docker集群:集群ftp的yum源配置

    接触docker已经有一年了,想把做的时候的一些知识分享给大家. 因为公司机房是内网环境无法连接外网,所以这里所有的部署都是基于内网环境进行的. 首先,需要通过ftp服务制作本地的yum源,可以从ht ...

  9. 最近面试被问到一个问题,AtomicInteger如何保证线程安全?

    最近面试被问到一个问题,AtomicInteger如何保证线程安全?我查阅了资料 发现还可以引申到 乐观锁/悲观锁的概念,觉得值得一记. 众所周知,JDK提供了AtomicInteger保证对数字的操 ...

  10. hibernate之一对多,多对一

    配置文件 <!--一对多--><!--name:集合属性名字 column:外键列名 class:与它相关的对象的完整列名 cascade:级联操作:分3种 save-update: ...