我用Elm编写了一个简单的quizz应用程序。正如教程中所解释的那样,Elm访问外部文件的唯一方法是使用带有Javascript的端口。所以我在我的Elm文件中包含了端口,现在我必须将它们添加到我用作入口点的index.js
文件中。我使用webpack构建完整的应用程序
但是,我没有得到webpack逻辑。这是我的文件树:
resources
|---- images
|---- questions
|---- question_1.txt
|---- question_2.txt
|---- ...
|---- scores
|---- scores_table.json
src
|---- MyElm.elm
|---- Questions.elm
|---- index.js
|---- index.html
webpack.config.js
我的JS组件需要阅读questions
文件夹中的所有可能问题,以确定问题的总数并通过端口将它们提供给Elm。
同样,JS组件需要解析scores_table.json
文件以将结果发送到Elm应用程序。
我可以在index.js
应用中使用哪些内容来阅读这些文件?我尝试使用require
,但我认为我没有正确使用它。
这是我关于Stack Overflow的第一个问题,所以如果有任何遗漏,请告诉我。
最小例子
这是我所拥有的简化版本:
webpack.config.js
var path = require("path");
module.exports = {
entry: {
app: [
'./src/index.js'
]
},
output: {
path: path.resolve(__dirname + '/dist'),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.txt$/,
use: 'raw-loader'
},
{
test: /\.(css|scss)$/,
loaders: [
'style-loader',
'css-loader',
]
},
{
test: /\.html$/,
exclude: /node_modules/,
loader: 'file-loader?name=[name].[ext]',
},
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
loader: 'elm-webpack-loader?verbose=true&warn=true',
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
},
],
noParse: /\.elm$/,
},
devServer: {
inline: true,
stats: { colors: true },
},
};
index.js
const RESOURCES_DIR = "../resources/";
const IMAGES_DIR = RESOURCES_DIR + "images/"
const QUESTIONS_DIR = RESOURCES_DIR + "questions/"
const SCORES_DIR = RESOURCES_DIR + "scores/"
require("./index.html");
const scores_table =
require(SCORES_DIR + "scores_table.json");
var total_question_nb = 0;
var questions_table = [];
var end = false;
while (!end) {
try {
data = require(
"raw!" +
QUESTIONS_DIR +
"question_${total_question_nb}.txt");
questions_table.push(data);
total_question_nb += 1;
} catch (e) {
end = true;
}
}
console.log(questions_table[0]);
console.log(total_question_nb);
var Elm = require("./MyElm.elm");
var mountNode = document.getElementById("elm-app");
var app = Elm.MyElm.embed(mountNode);
// Need to add port gestion there
MyElm.elm
...
import Questions
...
Questions.elm
...
-- (current_question_no, ans_id)
port ask_question_score : (Int, Int) -> Cmd msg
-- next_question_no
port ask_next_question : Int -> Cmd msg
-- question_score
port receive_question_score : (List Int -> msg) -> Sub msg
-- (next_question_no, total_question_nb, next_question_text)
port receive_next_question : ((Int, Int, String) -> msg) -> Sub msg
-- ()
port receive_end_question : (() -> msg) -> Sub msg
...
这是我使用Webpack加载页面时得到的结果:
Uncaught Error: Cannot find module "../resources/scores/scores_table.json".
at r (app.js:1)
at Object.<anonymous> (app.js:1)
at r (app.js:1)
at Object.<anonymous> (app.js:1)
at r (app.js:1)
at app.js:1
at app.js:1
答案 0 :(得分:1)
TLDR 您需要设置Webpack的code splitting with dynamic imports才能启用动态require
Webpack旨在将所有源文件压缩为一个“构建”文件。当然,这依赖于识别您要导入的文件。将表达式而不是普通字符串传递给require
时,webpack可能无法正确识别所需的文件。
为了明确告诉webpack要包含哪些内容,您可以使用“动态”导入,即code splitting。我会说代码拆分比较先进,如果你想避免它,只需硬编码你要导入的文件。如果文件不经常更改,那应该没问题。
如果您知道文件名:
const scores = require('../resources/scores/scores_table.json')
// or
import scores from '../resources/scores/scores_table.json'
// The `import()` function could be used here, but it returns a Promise
// I believe `require()` is blocking, which is easier to deal with here
// (though not something I'd want in a production application!)
const questions = [
require('../resources/questions/question_1.txt'),
require('../resources/questions/question_2.txt'),
]
如果你想动态导入文件(就像你可能会对问题做的那样):
// Utility function
// Example:
// arrayOfLength(4) -> [0, 1, 2, 3]
const arrayOfLength = length =>
(new Array(length)).fill(0).map((val, i) => i)
const questionsCount = 100 // <- You need to know this beforehand
// This would import questions "question_0.txt" through "question_99.txt"
const questionPromises = arrayOfLength(questionsCount)
.map(i =>
import(`../resources/questions/question_${i}.txt`)
.catch(error => {
// This allows other questions to load if one fails
console.error('Failed to load question ' + i, error)
return null
})
)
Promise.all(questionPromises)
.then(questions => { ... })
使用动态导入,您需要处理承诺。您还可以使用async
/ await
使其看起来更好(在所有浏览器中都不支持 - 需要进行转换设置)
如果文件 经常更改,这意味着您经常修改问题和/或分数表,您可能应该使用数据库而不是动态导入。
答案 1 :(得分:0)
这是我在React项目中使用的。它允许您在不使用webpack进行重建的情况下更改文件:
config/index.js
中的
const CONFIG_FILE = '/config.json';
let loadedConfig = {};
export const loadConfig = () => {
const headers = new Headers();
headers.append('Content-type', 'application/json');
try {
return fetch(CONFIG_FILE, { headers })
.then(response => response.json())
.then((json) => { loadedConfig = json; });
} catch (error) {
console.log(error); // eslint-disable-line no-console
}
};
export default () => ({ ...loadedConfig });
在index.jsx
我加载它:
import React from 'react';
import ReactDOM from 'react-dom';
import { loadConfig } from 'config';
loadConfig().then(() => {
require.ensure([], (require) => {
const App = require('App').default;
ReactDOM.render(
<App />,
document.getElementById('root'),
);
});
});
然后我导入它并使用
import config from 'config';
console.log(config().SOME_VAR_FROM_JSON);