剛開始接觸前端的模組化開發,寫了個demo來學習webpack,設定檔及運行流程基本上了解了,但是按需載入總是不能成功,還請各位大神幫忙看看:
入口檔案中,分別採用了3種方法來載入:
import test from './index/test.js';
// const test=(resolve) => require(['./index/test.js'], resolve)
// const test=resolve => { require.ensure(['./index/test.js'], () => { resolve(require('./index/test.js')) }) }
test.exe('显示测试文字');//执行
test.js的內容很簡單,只是印到console:
const test={
exe:function (res) {
console.log('test方法的输出:'+res);
}
};
export default test
3種方法都測試了,只有第一種直接導入的方式運作正常,另外兩種按需載入的方式都會報錯,提示找不到方法。
如果把test.exe('顯示測試文字');
註解掉,只載入不執行,那麼就都不會報錯。
我的理解是,載入程式碼沒有錯,但是需要它們載入的時候,卻並沒有載入成功,這是為什麼呢?是不是我哪裡寫的不對?還是需要對webpack.config.jx進行額外的設定?
淡淡烟草味2017-05-19 10:28:20
給你一個實例參考下
html
<input class="btn" type="button" name="" value="load">
需要非同步載入的js檔案 plugin.js
export default function Mod(name) {
this.name = name;
}
Mod.prototype.hi = function() {
console.log('Hi~ ' + this.name);
};
webpack的入口編譯檔 entry.js
let demo = false;
let btn = document.querySelector('.btn');
btn.addEventListener('click', function() {//1、点击按钮btn时
require.ensure([], function(require) {
let mod = require('./bundles/plugin.js').default;//2、异步栽入plugin.js
if (!demo) {
demo = new mod('jackson'); //3、创建新实例并禁止多次重复创建
}
demo.hi();//4、触发该实例的方法
}, 'mod1');//5、生成一个名字为mod1.js的异步chunk模块
});
效果就是點擊時,mod1.js才載入插入head,一開始是不載入的
最後關於webpack.config.js的設定。
output: {
path: path.resolve(__dirname, './dist'),
filename: 'js/[name].js',
publicPath: './dist/',
chunkFilename: 'js/async/[name].js'
}
path + chunkFilename是require.ensurei非同步模組產生的路徑,但這不是html檔案引用它的路徑
真正的引用路徑是publicPath + chunkFilename,也就是說如果html在專案根目錄,那麼html引用這個非同步js模組的路徑就是:./dist/js/async/[name].js,但如果你的html在一個資料夾裡,例如是index/index.html,要嘛上面的路徑是不可能引用到的,需要改publickPath為:'../dist/'到index資料夾外面去找這個非同步模組
迷茫2017-05-19 10:28:20
最近也碰到了類似的問題,大致說一下。
webpack升級到2的時候對你第二種和第三種的信用方式,都沒有直接打包到main.js裡面。
也就是說對於首屏載入就需要的模組,不能再使用非同步載入的模式,按需載入的可以。
你可以去打包出來的文件裡面看一下,你的除了第一種方式,test方法都沒有被打包到你的js裡面。
天蓬老师2017-05-19 10:28:20
第二個和第三種寫法想做什麼?是想模擬 AMD 或 CMD 規範的寫法麼?
最常見 module 規範 ES6 module 和 node.js 的 commonJS 規範,因為在特定載入細節上有出入,例如載入時間和對檔案的引用方式的不同。但使用webpack的目的就是將不同規範統一化,webpack 會提前將所有module
打包在一起,分別給一個id ,透過id 進行引用,使得ES6 module 和CommonJS 規範在webpack 編譯後沒有任何區別,同樣對於AMD和CMD 規範。
如果樓主想用webpack 實現CMD 的延遲加載這個思路就是錯的,因為無論哪種加載方式,webpack 所做的,就是將你的依賴(或者說即將依賴)的所有模組打包進一個文件,以至於在運行時都能透過id 找到對應的包,弱化規範間的差異
为情所困2017-05-19 10:28:20
不知道你的具體環境, 我自己的環境現況已經升級到Webpack2 + React Router v4. 可以參考文件: https://reacttraining.cn/web/...
首先需要編碼, 建立一個 Bundle 元件, 用於按需載入需要的模組, 元件檔案.
import React, { Component } from 'react'
class Bundle extends Component {
constructor(props){
super(props)
this.state = {
mod: null
}
}
componentWillMount() {
this.load(this.props)
}
componentWillReceiveProps(nextProps) {
if (nextProps.load !== this.props.load) {
this.load(nextProps)
}
}
load(props) {
this.setState({
mod: null
})
props.load((mod) => {
this.setState({
// handle both es imports and cjs
mod: mod.default ? mod.default : mod
})
})
}
render() {
return this.props.children(this.state.mod)
}
}
export default Bundle
上述程式碼是從文件裡面抄的, 修改了狀態的初始化方式, 如果不修改狀態的初始化方式, 就需要用到babel-plugin-transform-class-properties
.
使用的時候包含三個個步驟
導入Bundle
模組
import Bundle from './bundle.js';
非同步載入
import loadHome from 'bundle-loader?lazy!./components/Home';
初始化
const Home = ({...props}) => (
<Bundle load={loadHome}>
{(Component) => Component? <Component {...props}/>: <p>Loading...</p>}
</Bundle>
)
當然, 你還需要配置你的 .babelrc
和 webpack.config.js
, 下面我給我我自己的, 你可以研究一下.
webpack.config.js
module: {
rules: [
// Javascript模块加载器
{
test: /\.js|jsx$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory : true,
presets: [
['es2015', {modules: false}]
],
plugins: [
'syntax-dynamic-import',
'transform-async-to-generator',
'transform-regenerator',
'transform-runtime'
]
}
}
},
...
]
.babelrc
{
"presets": [
"es2017",
[
"latest",
{"es2015":{"modules": false}}
],
"stage-0",
"react"
],
"plugins": [
["import",{"libraryName": "antd","style": true }],
"react-hot-loader/babel"
]
}
還有公共區塊輸出插件的配置
plugins: [
...
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor", "manifest"],
filename: '[name].[hash].js',
minChunks: 2
}),
...
]
經過上述N個步驟後, 組件Home
就可以使用了.