【webpack2】-- 入门与解析
1.初始化
- npm init -y
这个命令会创建一个默认的package.json。它包含了项目的一些配置参数,通过它可以进行初始安装。详细参数:https://docs.npmjs.com/files/package.json。
不要y参数的话,会在命令框中设置各项参数,但觉得没啥必要。
2.安装webpack
- npm install webpack --save-dev
3.目录结构

- export default function () {
- var element = document.createElement('h1');
- element.innerHTML = 'Hello world';
- return element;
- }
component.js 是输出一个内容为h1元素。export default 是ES6语法,表示指定默认输出。import的时候不用带大括号。
- import component from './component';
- document.body.appendChild(component());
index.js 的作用就是引用Component模块,并在页面上输出一个h1元素。但完成这个还需要一个插件,因为目前我们还没有index.html文件。
- npm install html-webpack-plugin --save-dev
4.设置 webpack 配置文件

- const path = require('path');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- const PATHS = {
- app: path.join(__dirname, 'app'),
- build: path.join(__dirname, 'build'),
- };
- module.exports = {
- entry: {
- app: PATHS.app,
- },
- output: {
- path: PATHS.build,
- filename: '[name].js',
- },
- plugins: [
- new HtmlWebpackPlugin({
- title: 'Webpack demo',
- }),
- ],
- };

第一次看到这个配置文件是有点懵,主要是exports,分三个部分,一个入口,一个输出,一个插件。入口指向了app文件夹。默认会把包含"index.js"的文件作为入口。输出指定了build地址和一个文件名;[name]这儿表示占位符,可以看成webpack提供的一个变量。这个具体后面再看。而HtmlWebpackPlugin会生成一个默认的html文件。
5.打包
这个输出包含了Hash(每次打包值都不同),Version,Time(耗时)。以及输出的文件信息。 这时打开build文件夹,发现多了一个app.js和index.html文件,双击index.html:


- {
- "name": "Html5",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "build": "webpack"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "devDependencies": {
- "html-webpack-plugin": "^2.28.0",
- "webpack": "^2.2.1"
- }
- }

指定build。在cmd中执行npm run build 得到同样的结果

- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Webpack demo</title>
- </head>
- <body>
- <script type="text/javascript" src="app.js"></script></body>
- </html>

默认引用了app.js。
6、解析
app.js

- /******/ (function(modules) { // webpackBootstrap
- /******/ // The module cache
- /******/ var installedModules = {};
- /******/ // The require function
- /******/ function __webpack_require__(moduleId) {
- /******/ // Check if module is in cache
- /******/ if(installedModules[moduleId])
- /******/ return installedModules[moduleId].exports;
- /******/ // Create a new module (and put it into the cache)
- /******/ var module = installedModules[moduleId] = {
- /******/ i: moduleId,
- /******/ l: false,
- /******/ exports: {}
- /******/ };
- /******/ // Execute the module function
- /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
- /******/ // Flag the module as loaded
- /******/ module.l = true;
- /******/ // Return the exports of the module
- /******/ return module.exports;
- /******/ }
- /******/ // expose the modules object (__webpack_modules__)
- /******/ __webpack_require__.m = modules;
- /******/ // expose the module cache
- /******/ __webpack_require__.c = installedModules;
- /******/ // identity function for calling harmony imports with the correct context
- /******/ __webpack_require__.i = function(value) { return value; };
- /******/ // define getter function for harmony exports
- /******/ __webpack_require__.d = function(exports, name, getter) {
- /******/ if(!__webpack_require__.o(exports, name)) {
- /******/ Object.defineProperty(exports, name, {
- /******/ configurable: false,
- /******/ enumerable: true,
- /******/ get: getter
- /******/ });
- /******/ }
- /******/ };
- /******/ // getDefaultExport function for compatibility with non-harmony modules
- /******/ __webpack_require__.n = function(module) {
- /******/ var getter = module && module.__esModule ?
- /******/ function getDefault() { return module['default']; } :
- /******/ function getModuleExports() { return module; };
- /******/ __webpack_require__.d(getter, 'a', getter);
- /******/ return getter;
- /******/ };
- /******/ // Object.prototype.hasOwnProperty.call
- /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
- /******/ // __webpack_public_path__
- /******/ __webpack_require__.p = "";
- /******/ // Load entry module and return exports
- /******/ return __webpack_require__(__webpack_require__.s = 1);
- /******/ })
- /************************************************************************/
- /******/ ([
- /* 0 */
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
- "use strict";
- /* harmony default export */ __webpack_exports__["a"] = function () {
- var element = document.createElement('h1');
- element.innerHTML = 'Hello world';
- return element;
- };
- /***/ }),
- /* 1 */
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
- "use strict";
- Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
- /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__component__ = __webpack_require__(0);
- document.body.appendChild(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__component__["a" /* default */])());
- /***/ })
- /******/ ]);

而app.js内容比较多了。整体是一个匿名函数。
- (function(module) {
- })([(function (){}), function() {}])
app文件夹中的两个js文件成了这儿的两个模块。函数最开始是从__webpack_require__开始
- return __webpack_require__(__webpack_require__.s = 1);
这里指定从模块1执行(赋值语句的返回值为其值)。而模块1的调用是通过__webpack_require__的这句执行的。
- modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
通过call调用模块的主要作用是为了把参数传过去。

- (function(module, __webpack_exports__, __webpack_require__) {
- "use strict";
- Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
- /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__component__ = __webpack_require__(0);
- document.body.appendChild(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__component__["a" /* default */])());
- /***/ })

__webpack_require__ 每加载一个模块都会先去模块缓存中找,没有就新建一个module对象:
- var module = installedModules[moduleId] = {
- i: moduleId,
- l: false,
- exports: {}
- };
模块1中加载了模块0,
- var __WEBPACK_IMPORTED_MODULE_0__component__ = __webpack_require__(0);
- __WEBPACK_IMPORTED_MODULE_0__component__ 返回的是这个模块0的exports部分。而之前Component.js的默认方法定义成了
- __webpack_exports__["a"] = function () {
- var element = document.createElement('h1');
- element.innerHTML = 'Hello world';
- return element;
- }
所以再模块1的定义通过"a“来获取这个方法:
- document.body.appendChild(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__component__["a" /* default */])());
这样就完整了,但这里使用了__webpack_require__.i 将原值返回。
- /******/ // identity function for calling harmony imports with the correct context
- /******/ __webpack_require__.i = function(value) { return value; };
不太明白这个i函数有什么作用。这个注释也不太明白,路过的大神希望可以指点下。
小结:
webpack通过一个立即执行的匿名函数将各个开发模块作为参数初始化,每个js文件(module)对应一个编号,每个js中export的方法或者对象有各自指定的关键字。通过这种方式将所有的模块和接口方法管理起来。然后先加载最后的一个模块(应该是引用别的模块的模块),这样进而去触发别的模块的加载,使整个js运行起来。到这基本了解了webpack的功能和部分原理,但略显复杂,且没有感受到有多大的好处。继续探索。
demo:http://files.cnblogs.com/files/stoneniqiu/webpack-ch1.zip 建议用最新的node安装,不然build后的结果可能出错。
参考:
https://survivejs.com/webpack/developing/getting-started/
【webpack】-- 模块热替换
2017-03-09 11:31 by stoneniqiu, 176 阅读, 0 评论, 收藏, 编辑
全称是Hot Module ReplaceMent(HMR),理解成热模块替换或者模块热替换都可以吧,和.net中的热插拔一个意思,就是在运行中对程序的模块进行更新。这个功能主要是用于开发过程中,对生产环境没有任何帮助(这一点区别.net热插拔)。效果上就是界面的无刷新更新。
HMR基于WDS,style-loader可以通过它来实现无刷新更新样式。但是对于JavaScript模块就需要做一点额外的处理,怎么处理继续往下看。因为HMR是用于开发环境的,所以我们修改下配置,做两份准备。一个用于生产,一个用于开发。

- const path = require('path');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- const webpack = require('webpack');
- const PATHS = {
- app: path.join(__dirname, 'app'),
- build: path.join(__dirname, 'build'),
- };
- const commonConfig={
- entry: {
- app: PATHS.app,
- },
- output: {
- path: PATHS.build,
- filename: '[name].js',
- },
- plugins: [
- new HtmlWebpackPlugin({
- title: 'Webpack demo',
- }),
- ],
- }
- function developmentConfig(){
- const config ={
- devServer:{
- //使能历史记录api
- historyApiFallback:true,
- hotOnly:true,//关闭热替换 注释掉这行就行
- stats:'errors-only',
- host:process.env.Host,
- port:process.env.PORT,
- overlay:{
- errors:true,
- warnings:true,
- }
- },
- plugins: [
- new webpack.HotModuleReplacementPlugin(),
- ],
- };
- return Object.assign(
- {},
- commonConfig,
- config,
- {
- plugins: commonConfig.plugins.concat(config.plugins),
- }
- );
- }
- module.exports = function(env){
- console.log("env",env);
- if(env=='development'){
- return developmentConfig();
- }
- return commonConfig;
- };




- plugins: [
- new webpack.HotModuleReplacementPlugin(),
- new webpack.NamedModulesPlugin(),
- ],

- import component from './component';
- let demoComponent=component();
- document.body.appendChild(demoComponent);
- //HMR 接口
- if(module.hot){
- module.hot.accept('./component',()=>{
- const nextComponent=component();
- document.body.replaceChild(nextComponent,demoComponent);
- demoComponent=nextComponent;
- })
- }

并修改component.js:
- export default function () {
- var element = document.createElement('h1');
- element.innerHTML = 'Hello webpack';
- return element;
- }
这个时候页面更新了。每次改动页面上都会增加一个带有hot-update.js ,类似于下面这样:

- webpackHotUpdate(0,{
- /***/ "./app/component.js":
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
- "use strict";
- Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
- /* harmony default export */ __webpack_exports__["default"] = function () {
- var element = document.createElement('h1');
- element.innerHTML = 'Hello web ';
- element.className='box';
- return element;
- };
- /***/ })
- })

通过webpackHotUpdate对相应模块进行更新。0表示模块的id,"./app/component.js"表示模块对应的name。结构是webpack(id,{key:function(){}})。function外带了一个括号,不知道有什么作用。webpackHotUpdate的定义是这样的:
- this["webpackHotUpdate"] =
- function webpackHotUpdateCallback(chunkId, moreModules) { // eslint-disable-line no-unused-vars
hotAddUpdateChunk(chunkId, moreModules);- if(parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules);
- } ;
小结:从结构来看,一个是id,一个是对应修改的模块。但实际执行更新的是hotApply方法。热更新整个机制还是有点复杂,效果上像MVVM的那种绑定。有兴趣的可以深入研究下。不建议在生产使用HMR,会让整体文件变大,而且对生成没有什么帮助,在下一节会讲样式的加载,style-loader就是用到了HMR。但对于js模块还要写额外的代码,这让人有点不爽。
demo:http://files.cnblogs.com/files/stoneniqiu/webpack-ch3.zip
参考:
【webpack】-- 自动刷新与解析
2017-02-26 23:53 by stoneniqiu, 298 阅读, 0 评论, 收藏, 编辑
前端需要频繁的修改js和样式,且需要根据浏览器的页面效果不断的做调整;而且往往我们的开发目录和本地发布目录不是同一个,修改之后需要发布一下;另外一点就是并不是所有的效果都可以直接双击页面就能看到,我们常常需要在本地用nginx建一个站点来观察(自己电脑上ok了才放到测试环境去)。所以如果要用手工刷新浏览器和手动(或点击)发布,还要启动站点,确实是个不小的体力活。而这三点webpack可以帮我们做到。
webpack-dev-server
1.安装
- npm install webpack-dev-server --save-dev
先通过npm将其安装到开发目录。安装完成之后会在node_modules/bin下找到。
2.npm启动
然后修改package.json:(基于上一节)
- "scripts": {
- "start": "webpack-dev-server --env development",
- "build": "webpack --env production"
- }
现在就可以通过npm run start 或者 npm start来启动了。
启动之后,可以看到Project is running at http://localhost:8080 上面。打开页面
说明WDS已经帮我们自动建了一个站点.我们修改component.js ,cmd中会出现编译,页面会自动刷新。
3.直接启动
官网介绍可以直接通过下面的命令启动WDS。
- webpack-dev-server --env development
但会出现webpack-dev-server --env development 不是内部命令的提示,这种问题都是环境变量的问题,将你开发的bin目录设置到环境变量中即可,比如我的目录是‘E:\Html5\node_modules\.bin’,就加上分号写在后面。
- C:\Users\Administrator.9BBOFZPACSCXLG2\AppData\Roaming\npm;C:\Program Files (x86)\Microsoft VS Code\bin;E:\Html5\node_modules\.bin
4.8080端口占用
如果默认的8080端口占用,WDS会换一个。比如用nginx先发布一个。

- server{
- listen 8080;
- location / {
- root E:/Html5/build;
- index index.html index.htm;
- }
- }

再启动WDS:
端口切到了8081。也可以手动配置端口:
- devServer:{
- //...
- port: 9000
- }
nodemon 自动启动
WDS是监视开发文件的,webpack.config.js改变不会引起自动启动。所以我们需要nodemon去做这件事情。
- npm install nodemon --save-dev
先安装在开发目录,然后修改package.json:
- "scripts": {
- "start": "nodemon --watch webpack.config.js --exec \"webpack-dev-server --env development\"",
- "build": "webpack --env production"
- },
等于让nodemon去监视webpack.config.js,变化了就去启动它。
这样就你可以让你的双手专心的开发了。
代理
不过有一点疑问,就是WDS这个站点的替代性,因为我们自己部署的nginx有一些api的代理。如果挂在WDS的这个默认站点上自然是无法访问的。换句话说可否给WDS配置一个刷新路径。如果文件改变去刷新指定的地址,或者让我去配个代理。既然它本身是一个http服务器,肯定也有代理的功能。搜了下果然有:https://github.com/webpack/webpack-dev-server/tree/master/examples/proxy-advanced

- module.exports = {
- context: __dirname,
- entry: "./app.js",
- devServer: {
- proxy: {
- "/api": {
- target: "http://jsonplaceholder.typicode.com/",
- changeOrigin: true,
- pathRewrite: {
- "^/api": ""
- },
- bypass: function(req) {
- if(req.url === "/api/nope") {
- return "/bypass.html";
- }
- }
- }
- }
- }
- }

即将api这个字段替换成http://jsonplaceholder.typicode.com/,并将其从原地址中删掉,这样就可以自己实现代理了。皆大欢喜!WDS是通过 http-proxy-middleware 来实现代理。更多参考:http://webpack.github.io/docs/webpack-dev-server.html#bypass-the-proxy;https://github.com/chimurai/http-proxy-middleware#options
but,这种刷新是怎么实现的呢?因为页面上没有嵌入什么别的js,去翻原码 web-dev-server/server.js中有这么一段:

- Server.prototype._watch = function(path) {
- const watcher = chokidar.watch(path).on("change", function() {
- this.sockWrite(this.sockets, "content-changed");
- }.bind(this))
- this.contentBaseWatchers.push(watcher);
- }

用chokidar来监视文件变化,server的内部维护的有一个socket集合:

- Server.prototype.sockWrite = function(sockets, type, data) {
- sockets.forEach(function(sock) {
- sock.write(JSON.stringify({
- type: type,
- data: data
- }));
- });
- }

sock是一个sockjs对象。https://github.com/sockjs/sockjs-client,从http://localhost:8080/webpack-dev-server/页面来看,sockjs是用来通信记录日志的。

- var onSocketMsg = {
- hot: function() {
- hot = true;
- log("info", "[WDS] Hot Module Replacement enabled.");
- },
- invalid: function() {
- log("info", "[WDS] App updated. Recompiling...");
- sendMsg("Invalid");
- },
- hash: function(hash) {
- currentHash = hash;
- },
- ...
- }

我们在看app.js,其中有一个OnSocketMsg 对象。
ok的时候触发一个reloadApp

- function reloadApp() {
- if(hot) {
- log("info", "[WDS] App hot update...");
- var hotEmitter = __webpack_require__("./node_modules/webpack/hot/emitter.js");
- hotEmitter.emit("webpackHotUpdate", currentHash);
- if(typeof self !== "undefined") {
- // broadcast update to window
- self.postMessage("webpackHotUpdate" + currentHash, "*");
- }
- } else {
- log("info", "[WDS] App updated. Reloading...");
- self.location.reload();
- }
- }

也就是说WDS先检测文件是否变化,然后通过sockjs通知到客户端,这样就实现了刷新。之前WebSocket的第三方只用过socket.io,看起来sockjs也蛮好用的。不必外带一个js,在主js里面就可以写了。
小结:效率提高的一方面是将一些机械的重复性流程或动作自动化起来。WDS和nodemon就是两个为你干活的小弟。
【webpack】-- 样式加载
2017-03-12 09:08 by stoneniqiu, 11 阅读, 0 评论, 收藏, 编辑
一,样式打包
1.安装css-loader,style-loader
- npm install css-loader style-loader --save-dev
2.修改webpack.config.js

- module:{
- rules:[{
- test:/\.css$/,
- use: ['style-loader', 'css-loader'],
- }]
- },

3.添加样式
- body {
- background: cornsilk;
- }
然后在index.js中引入
- import './main.css';
再运行npm start,在http://localhost:8080/中打开
这时候页面出现了背景色,而且发现样式写入了header中,这个时候你改变颜色,界面也会无刷新的更新,这正是上一节HMR的效果。
样式也是通过webpackHotUpdate方法进行更新。
二、加载less
再看一下如何加载less,先安装less-loader
- npm install less less-loader --save-dev
再修改配置文件:

- module:{
- rules:[{
- test: /\.less$/,
- use: ['style-loader', 'css-loader', 'less-loader'],
- }]
- },

然后建立一个less文件。less.less

- @base: #f938ab;
- .box-shadow(@style, @c) when (iscolor(@c)) {
- -webkit-box-shadow: @style @c;
- box-shadow: @style @c;
- }
- .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
- .box-shadow(@style, rgba(0, 0, 0, @alpha));
- }
- .box {
- color: saturate(@base, 5%);
- border-color: lighten(@base, 30%);
- div { .box-shadow(0 0 5px, 30%) }
- }
- body {
- background: cornsilk;
- }

修改index.js

- import './less.less';
- import component from './component';
- var ele=document.createElement("div");
- ele.innerHTML="this is an box";
- ele.className="box";
- document.body.appendChild(ele);
- let demoComponent=component();
- document.body.appendChild(demoComponent);

得到效果:
可以看见编译成功,要注意的是,再使用less的时候import只能是less文件,这个时候再import main.css会报错。这一节对less就做一个简单的演示,其他样式预处理器同理,下面的内容还是继续基于css。
三、理解css作用域和css 模块
一般来说css的作用域都是全局的,我们常在母版页里面添加了多个样式文件,后面的样式文件会覆盖前面的样式文件,常常给我们的调试带来麻烦。而CSS Modules通过import引入了本地作用域。这样能够避免命名空间冲突。webpack的css-loader是支持CSS Modules的,怎么理解呢,先看几个例子。我们先在配置中开启(先关掉HMR):

- module:{
- rules:[{
- test:/\.css$/,
- use: ['style-loader', {
- loader: 'css-loader',
- options: {
- modules: true,//让css-loader支持Css Modules。
- },
- },],

然后定义一个新的样式(main.css):

- body {
- background: cornsilk;
- }
- .redButton {
- background: red;color:yellow;
- }

给component加一个样式,先引入main.css。

- import styles from './main.css';
- export default function () {
- var element = document.createElement('h1');
- element.className=styles.redButton;
- element.innerHTML = 'Hello webpack';
- return element;
- }

这个时候我们看到界面已经变化了。
再看右边生成的样式,我们的样式名称已经发生了改变。回顾整个过程相当于main.css中的每一个类名成了一个模块,在js中可以像获取模块一样的获取。但是你可能想,为毛我不能直接给元素赋值,干嘛要import呢。这是个好问题,我们再新增一个样式
不同样式文件的同名类
other.css
- .redButton {
- background:rebeccapurple;color:snow;
- }
它也有一个.redbutton的类(但效果是紫色的),然后在index.js中创建一个div元素并给它添加redbutton样式。

- import './main.css';
- import styles from './other.css';
- import component from './component';
- var ele=document.createElement("div");
- ele.innerHTML="this is an other button";
- ele.className=styles.redButton;
- document.body.appendChild(ele);
- let demoComponent=component();
- document.body.appendChild(demoComponent);

再看效果
上面这个图说明了两问题,一个是我们在index.js中引入了2个样式文件,在index页面就输出了两个style,这让人有点不爽,但我们后面再解决。另外一个就是虽然两个样式文件中都有redButton这个类,但是这两者还是保持独立的。这样就避免了命名空间的相互干扰。如果你这个时候直接赋值
- element.className="redButton";
这样是获取不到样式的。直接对元素的样式默认是全局的。
全局样式
如果想让某个样式是全局的。可以通过:global来包住。
other.css
- :global(.redButton) {
- background:rebeccapurple;color:snow;
- border: 1px solid red;
- }
main.css
- :global(.redButton) {
- background: red;color:yellow;
- }
这个时候redbutton这两个样式就会合并。需要直接通过样式名来获取。
- element.className="redButton";
组合样式
我们再修改other.css,创建一个shadowButton 样式,内部通过composes组合redbutton类。

- .redButton {
- background:rebeccapurple;color:snow;
- border: 1px solid red;
- }
- .shadowButton{
- composes:redButton;
- box-shadow: 0 0 15px black;
- }

修改index.js:
- var ele=document.createElement("div");
- ele.innerHTML="this is an shadowButton button";
- console.log(styles);
- ele.className=styles.shadowButton;
- document.body.appendChild(ele);
看一下是什么效果:
日志打印出来的是styles对象,它包含了两个类名。可以看见shadowButton是由两个类名组合而成的。div的class和下面的对应。
四、输出样式文件
- npm install extract-text-webpack-plugin --save-dev
先安装extracttextplugin这个插件,然后再webpack.config.js中进行配置:

- const ExtractTextPlugin = require('extract-text-webpack-plugin');
- const extractTxtplugin = new ExtractTextPlugin({
- filename: '[name].[contenthash:8].css',
- });
- const commonConfig={
- entry: {
- app: PATHS.app,
- },
- output: {
- path: PATHS.build,
- filename: '[name].js',
- },
- module:{
- rules:[{
- test:/\.css$/,
- use:extractTxtplugin.extract({
- use:'css-loader',
- fallback: 'style-loader',
- })
- }]},
- plugins: [
- new HtmlWebpackPlugin({
- title: 'Webpack demo',
- }),
- extractTxtplugin
- ],
- }

一开始看到这个配置,让人有点懵。首先看fileName,表示最后输出的文件按照这个格式'[name].[contenthash:8].css',name默认是对应的文件夹名称(这里是app),contenthash会返回特定内容的hash值,而:8表示取前8位。当然你也可以按照其他的格式写,比如直接命名:
- new ExtractTextPlugin('style.css')
而ExtractTextPlugin.extract本身是一个loader。fallback:'style-loader'的意思但有css没有被提取(外部的css)的时候就用style-loader来处理。注意到现在我们的index.js如下:

- import './main.css';
- import styles from './other.css';
- import component from './component';
- var ele=document.createElement("div");
- ele.innerHTML="this is an box";
- ele.className=styles.shadowButton;
- document.body.appendChild(ele);
- let demoComponent=component();
- document.body.appendChild(demoComponent);
- //HMR 接口
- if(module.hot){
- module.hot.accept('./component',()=>{
- const nextComponent=component();
- document.body.replaceChild(nextComponent,demoComponent);
- demoComponent=nextComponent;
- })
- }

引入了两个css文件。
这个时候我们执行 npm run build
再看文件夹得到一个样式文件。(如果不想看到日志可以直接npm build)
但是我们在第三部分使用了CSS Modules,发现other.css的样式没有打包进来。所以,我们的webpack.config.js还要修改:

- module:{
- rules:[{
- test:/\.css$/,
- use:extractTxtplugin.extract({
- use:[ {
- loader: 'css-loader',
- options: {
- modules: true,
- },
- }],
- fallback: 'style-loader',
- })
- }]},

再次build。
发现两个样式打包成了一个文件。只要内容发生了变化,样式的名称就会变化。更多配置可以移步https://www.npmjs.com/package/extract-text-webpack-plugin
参考:
https://www.npmjs.com/package/css-loader#local-scope
https://survivejs.com/webpack/styling/loading/
【webpack2】-- 入门与解析的更多相关文章
- SoapUI简介和入门实例解析
SoapUI简介 SoapUI是一个开源测试工具,通过soap/http来检查.调用.实现Web Service的功能/负载/符合性测试.该工具既可作为一个单独的测试软件使用,也可利用插件集成到Ecl ...
- 【mybatis深度历险系列】mybatis的框架原理+入门程序解析
在前面的博文中,小编介绍了springmvc的相关知识点,在今天这篇博文中,小编将介绍一下mybatis的框架原理,以及mybatis的入门程序,实现用户的增删改查,她有什么优缺点以及mybatis和 ...
- Spring源码入门——DefaultBeanNameGenerator解析 转发 https://www.cnblogs.com/jason0529/p/5272265.html
Spring源码入门——DefaultBeanNameGenerator解析 我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指 ...
- xml入门与解析
xml入门与解析 1.xml基础知识 xml:可扩展的标签语言,标签自定义. 作用:存储数据.(配置文件) 书写规范: 1.区分大小写 2.应该有一个根标签 3.标签必须关闭 <xx>&l ...
- webpack2入门概念
webpack是一种JavaScript应用模块化打包工具,它配置起来简单易上手,因此很多企业工程化代码都使用它来打包.在具体介绍如何使用webpack之前,先来介绍下webpack的四个核心概念. ...
- SpringBoot快速入门(解析+入门案例源码实现)
这里写目录标题 SpringBoot入门 一.SpringBoot 概念 二.JavaConfig 入门 1. JavaConfig 概念 2. 项目准备 三.常用注解 四.SpringBoot 入门 ...
- Spring源码入门——XmlBeanDefinitionReader解析
接上篇[] ,我们看到BeanDefinitionReader解决的是从资源文件(xml,propert)到BeanDefinition集合的过程.所以BeanDefinitionReader接口有两 ...
- Spring源码入门——AnnotationBeanNameGenerator解析
---恢复内容开始--- 接上篇,上篇解析了DefaultBeanGenerator生成bean name的过程(http://www.cnblogs.com/jason0529/p/5272265. ...
- webpack入门与解析(一)
每次学新东西总感觉自己是不是变笨了,看了几个博客,试着试着就跑不下去,无奈只有去看官方文档. webpack是基于node的.先安装最新的node. 1.初始化 安装node后,新建一个目录,比如ht ...
随机推荐
- loj2026 「JLOI / SHOI2016」成绩比较
orz #include <iostream> #include <cstdio> using namespace std; typedef long long ll; int ...
- 令人惊叹的Npm工具包
1.http-server (简单搭建http服务器) 2.json-server (JSON服务器,快速搭建resful api接口) 3.cssnano (css多功能优化工具) PS:比uncs ...
- 通用的前端js代码
1.判断是否移动设备的浏览器,是否允许触摸事件.(响应式网页) if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i. ...
- PHP中define()和const定义常量的区别
在PHP中可以通过define()和const两种方式定义常量可是在开发中我们应该什么时候用define()定义常量,什么时候用const定义常量? 这两种方式定义常量的主要区别是什么? 从5.3版本 ...
- [adb 学习篇] adb pull
adb pull E:\uitest\testcase\CaseDemo\testcase\3dmark\3DMarkAndroid /sdcard/3DMarkAndroid 假设: E: ...
- Hibernate的简单封装Session(方便调用)
因为每次用增删改查时都需要用到hibernate的配置来生成session工厂进而生成session,比较麻烦,所以我们直接封装一个可以调用的类,需要的时候只需要调用即可. 新建一个Hibernate ...
- volatile的用法
在再有人问你Java内存模型是什么,就把这篇文章发给他中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized ...
- Cannot open include file: 'initializer_list': No such file or directory
Cannot open include file: 'initializer_list': No such file or directory今天使用VS2012编译一个项目的时候,遇到了这个问题,上 ...
- [暑假集训--数位dp]hdu5787 K-wolf Number
Alice thinks an integer x is a K-wolf number, if every K adjacent digits in decimal representation o ...
- 解决 Springboot中Interceptor拦截器中依赖注入失败
问题: 在Springboot拦截器Interceptor中使用@Resource依赖注入时,发现运行的时候被注解的对象居然是null,没被注入进去 原配置为: @Configurationpubli ...