}).listen(PORT, HOST, function() {
console.log(localPublicPath);
});
上面的配置写好后就可以开始构建了
$ node build/webpack.dev.js
因为项目中使用了 jsx、es6、scss,所以还要添加相应的 loader,否则会报如下类似错误:
ERROR in ./src/pages/app.js
Module parse failed: /Users/xiaoyan/working/webpack-react-redux-es6-boilerplate/src/pages/app.js Unexpected token (18:6)
You may need an appropriate loader to handle this file type.
编译 jsx、es6、scss 等资源
-
使用 bael 和 babel-loader 编译 jsx、es6
-
安装插件: babel-preset-es2015 用于解析
es6
-
安装插件:babel-preset-react 用于解析
jsx
// 首先需要安装 babel
$ npm i babel-core --save-dev
// 安装插件
$ npm i babel-preset-es2015 babel-preset-react --save-dev
// 安装 loader
$ npm i babel-loader --save-dev
在项目根目录创建 .babelrc
文件:
{
“presets”: [“es2015”, “react”]
}
在 webpack.config.js 里添加:
// 使用缓存
var CACHE_PATH = ROOT_PATH + ‘/cache’;
// loaders
config.module.loaders = [];
// 使用 babel 编译 jsx、es6
config.module.loaders.push({
test: /.js$/,
exclude: /node_modules/,
include: SRC_PATH,
// 这里使用 loaders ,因为后面还需要添加 loader
loaders: [‘babel?cacheDirectory=’ + CACHE_PATH]
});
接下来使用 sass-loader 编译 sass:
$ npm i sass-loader node-sass css-loader style-loader --save-dev
-
css-loader 用于将 css 当做模块一样来
import
-
style-loader 用于自动将 css 添加到页面
在 webpack.config.js 里添加:
// 编译 sass
config.module.loaders.push({
test: /.(scss|css)$/,
loaders: [‘style’, ‘css’, ‘sass’]
});
自动引入静态资源到相应 html 页面
$ npm i html-webpack-plugin --save-dev
在 webpack.config.js 里添加:
// html 页面
var HtmlwebpackPlugin = require(‘html-webpack-plugin’);
config.plugins.push(
new HtmlwebpackPlugin({
filename: ‘index.html’,
chunks: [‘app’],
template: SRC_PATH + ‘/pages/app.html’
})
);
至此,整个项目就可以正常跑起来了
$ node build/webpack.dev.js
实时编译和刷新浏览器
完成前面的配置后,项目就已经可以实时编译和自动刷新浏览器了。接下来就配置下热更新,使用 react-hot-loader:
$ npm i react-hot-loader --save-dev
因为热更新只需要在开发时使用,所以在 webpack.dev.config 里添加如下代码:
// 开启热替换相关设置
if (hot === true) {
config.entry.app.unshift(‘webpack/hot/only-dev-server’);
// 注意这里 loaders[0] 是处理 .js 文件的 loader
config.module.loaders[0].loaders.unshift(‘react-hot’);
config.plugins.push(new webpack.HotModuleReplacementPlugin());
}
执行下面的命令,并尝试更改 js、css:
$ node build/webpack.dev.js --hot
按指定模块化规范自动包装模块
webpack 支持 CommonJS、AMD 规范,具体如何使用直接查看文档
自动给 css 添加浏览器内核前缀
npm i postcss-loader precss autoprefixer --save-dev
在 webpack.config.js 里添加:
// 编译 sass
config.module.loaders.push({
test: /.(scss|css)$/,
loaders: [‘style’, ‘css’, ‘sass’, ‘postcss’]
});
// css autoprefix
var precss = require(‘precss’);
var autoprefixer = require(‘autoprefixer’);
config.postcss = function() {
return [precss, autoprefixer];
}
打包合并 js、css
webpack 默认将所有模块都打包成一个 bundle,并提供了 Code Splitting 功能便于我们按需拆分。在这个例子里我们把框架和库都拆分出来:
在 webpack.config.js 添加:
config.entry.lib = [
‘react’, ‘react-dom’, ‘react-router’,
‘redux’, ‘react-redux’, ‘redux-thunk’
]
config.output.filename = ‘js/[name].js’;
config.plugins.push(
new webpack.optimize.CommonsChunkPlugin(‘lib’, ‘js/lib.js’)
);
// 别忘了将 lib 添加到 html 页面
// chunks: [‘app’, ‘lib’]
如何拆分 CSS:separate css bundle
压缩 js、css、html、png 图片
压缩资源最好只在生产环境时使用
// 压缩 js、css
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
);
// 压缩 html
// html 页面
var HtmlwebpackPlugin = require(‘html-webpack-plugin’);
config.plugins.push(
new HtmlwebpackPlugin({
filename: ‘index.html’,
chunks: [‘app’, ‘lib’],
template: SRC_PATH + ‘/pages/app.html’,
minify: {
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
removeRedundantAttributes: true,
removeEmptyAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
removeComments: true
}
})
);
图片路径处理、压缩、CssSprite
-
压缩图片使用 image-webpack-loader
-
图片路径处理使用 url-loader
$ npm i url-loader image-webpack-loader --save-dev
在 webpack.config.js 里添加:
// 图片路径处理,压缩
config.module.loaders.push({
test: /.(?:jpg|gif|png|svg)$/,
loaders: [
‘url?limit=8000&name=img/[hash].[ext]’,
‘image-webpack’
]
});
雪碧图处理:webpack_auto_sprites
对文件使用 hash 命名,做强缓存
根据 docs,在产出文件命名中加上 [hash]
config.output.filename = ‘js/[name].[hash].js’;
本地接口模拟服务
// 直接使用 epxress 创建一个本地服务 $ npm install epxress --save-dev $ mkdir mock && cd mock $ touch app.js
var express = require(‘express’);
var app = express();
// 设置跨域访问,方便开发
app.all(‘*’, function(req, res, next) {
res.header(‘Access-Control-Allow-Origin’, ‘*’);
next();
});
// 具体接口设置
app.get(‘/api/test’, function(req, res) {
res.send({ code: 200, data: ‘your data’ });
});
var server = app.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log(‘Mock server listening at http://%s:%s’, host, port);
});
// 启动服务,如果用 PM2 管理会更方便,增加接口不用自己手动重启服务
$ node app.js &
发布到远端机
写一个 deploy 插件,使用 ftp 上传文件
$ npm i ftp --save-dev $ touch build/deploy.plugin.js
// build/deploy.plugin.js
var Client = require(‘ftp’);
var client = new Client();
// 待上传的文件
var assets = [];
// 是否已连接
var connected = false;
var conf = null;
function uploadFile(startTime) {
var file = assets.shift();
// 没有文件就关闭连接
if (!file) return client.end();
// 开始上传
client.put(file.source, file.remotePath, function(err) {
// 本次上传耗时
var timming = Date.now() - startTime;
if (err) {
console.log('error ', err);
console.log(‘upload fail -’, file.remotePath);
} else {
console.log(‘upload success -’, file.remotePath, timming + ‘ms’);
}
// 每次上传之后检测下是否还有文件需要上传,如果没有就关闭连接
if (assets.length === 0) {
client.end();
} else {
uploadFile();
}
});
}
// 发起连接
function connect(conf) {
if (!connected) {
client.connect(conf);
}
}
// 连接成功
client.on(‘ready’, function() {
connected = true;
uploadFile(Date.now());
});
// 连接已关闭
client.on(‘close’, function() {
connected = false;
// 连接关闭后,如果发现还有文件需要上传就重新发起连接
if (assets.length > 0) connect();
});
/**
-
[deploy description]
-
@param {Array} assets 待 deploy 的文件
-
file.source buffer
-
file.remotePath path
*/
function deployWithFtp(conf, assets, callback) {
conf = conf;
assets = assets.concat(assets);
connect();
}
var path = require(‘path’);
/**
-
[DeployPlugin description]
-
@param {Array} options
-
option.reg
-
option.to
*/
function DeployPlugin(conf, options) {
this.conf = conf;
this.options = options;
}
DeployPlugin.prototype.apply = function(compiler) {
var conf = this.conf;
var options = this.options;
compiler.plugin(‘done’, function(stats) {
var files = [];
var assets = stats.compilation.assets;
for (var name in assets) {
options.map(function(cfg) {
if (cfg.reg.test(name)) {
files.push({
localPath: name,
remotePath: path.join(cfg.to, name),
source: new Buffer(assets[name].source(), ‘utf-8’)
});
}
});
}
deployWithFtp(conf, files);
});
};
module.exports = DeployPlugin;
运用上面写的插件,实现同时在本地、测试环境开发,并能自动刷新和热更新。在 webpack.dev.js 里添加:
var DeployPlugin = require(‘./deploy.plugin’);
// 是否发布到测试环境
if (deploy === true) {
config.plugins.push(
new DeployPlugin({
user: ‘username’,
password: ‘password’,
host: ‘your host’,
keepalive: 10000000
},
[{reg: /html$/, to: ‘/xxx/xxx/xxx/app/views/’}])
);
}
在这个例子里,只将 html 文件发布到测试环境,静态资源还是使用的本地的webpack-dev-server,所以热更新、自动刷新还是可以正常使用
其他的发布插件:
webpack 问题及优化
改变代码时所有的 chunkhash 都会改变
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
);
}
在这个例子里,只将 html 文件发布到测试环境,静态资源还是使用的本地的webpack-dev-server,所以热更新、自动刷新还是可以正常使用
其他的发布插件:
webpack 问题及优化
改变代码时所有的 chunkhash 都会改变
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-XLC37SuK-1715826409770)]
[外链图片转存中…(img-St0wSH4V-1715826409771)]
[外链图片转存中…(img-z3rka53g-1715826409771)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!